diff --git a/Makefile b/Makefile index f58b70e..554fe72 100644 --- a/Makefile +++ b/Makefile @@ -322,6 +322,7 @@ SOURCES += gui/message_option_t.cc SOURCES += gui/message_stats_t.cc SOURCES += gui/messagebox.cc SOURCES += gui/money_frame.cc +SOURCES += gui/onewaysign_info.cc SOURCES += gui/optionen.cc SOURCES += gui/pakselector.cc SOURCES += gui/password_frame.cc @@ -521,9 +522,9 @@ ifeq ($(BACKEND),sdl2) SOURCES += simsys_s2.cc ifeq ($(OSTYPE),mac) # Core Audio (Quicktime) base sound system routines - SOURCES += sound/core-audio_sound.mm - SOURCES += music/core-audio_midi.mm - LIBS += -framework Foundation -framework QTKit + SOURCES += sound/sdl_mixer_sound.cc + SOURCES += music/sdl_midi.cc + LIBS += -framework Foundation -lSDL_mixer else SOURCES += sound/sdl_sound.cc ifeq ($(findstring $(OSTYPE), cygwin mingw),) diff --git a/boden/wege/weg.cc b/boden/wege/weg.cc index a2d0000..166c74f 100644 --- a/boden/wege/weg.cc +++ b/boden/wege/weg.cc @@ -235,6 +235,30 @@ void weg_t::info(cbuffer_t & buf) const buf.printf("%s%u", translator::translate("\nRibi (unmasked)"), get_ribi_unmasked()); buf.printf("%s%u\n", translator::translate("\nRibi (masked)"), get_ribi()); + if( get_waytype() == road_wt ) { + // Display overtaking_info + switch (get_overtaking_info()) { + case 0: + buf.printf("%s%s\n", translator::translate("Overtaking:"),translator::translate("one-way")); + break; + case 1: + buf.printf("%s%s\n", translator::translate("Overtaking:"),translator::translate("two-way")); + break; + case 2: + buf.printf("%s%s\n", translator::translate("Overtaking:"),translator::translate("only loading convoi")); + break; + case 3: + buf.printf("%s%s\n", translator::translate("Overtaking:"),translator::translate("prohibited")); + break; + case 4: + buf.printf("%s%s\n", translator::translate("Overtaking:"),translator::translate("passing lane only")); + break; + default: + buf.printf("%s%s\n", translator::translate("Overtaking:"),translator::translate("ERROR")); + break; + } + } + if(has_sign()) { buf.append(translator::translate("\nwith sign/signal\n")); } diff --git a/boden/wege/weg.h b/boden/wege/weg.h index f70bf45..61d8dc7 100644 --- a/boden/wege/weg.h +++ b/boden/wege/weg.h @@ -213,6 +213,12 @@ public: const char *get_name() const { return desc->get_name(); } /** + * Overtaking info (0 = condition for one-way road, 1 = condition for two-way road, 2 = overtaking a loading convoy only, 3 = overtaking is completely forbidden, 4 = vehicles can go only on passing lane) + * @author teamhimeH + */ + sint8 get_overtaking_info() const { return desc->get_overtaking_info(); } + + /** * Add direction bits (ribi) for a way. * * Nachdem die ribis geändert werden, ist das weg_image des diff --git a/descriptor/reader/way_reader.cc b/descriptor/reader/way_reader.cc index 5ac464e..efc8735 100644 --- a/descriptor/reader/way_reader.cc +++ b/descriptor/reader/way_reader.cc @@ -55,6 +55,7 @@ obj_desc_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node) desc->obsolete_date = DEFAULT_RETIRE_DATE*12; desc->wt = road_wt; desc->styp = type_flat; + desc->overtaking_info = 0; desc->draw_as_obj = false; desc->number_seasons = 0; } @@ -63,7 +64,22 @@ obj_desc_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node) const uint16 v = decode_uint16(p); version = v & 0x7FFF; - if(version==6) { + if(version==7) { + //version 7, now with overtaking_info + desc->cost = decode_uint32(p); + desc->maintenance = decode_uint32(p); + desc->topspeed = decode_uint32(p); + desc->max_weight = decode_uint32(p); + desc->intro_date = decode_uint16(p); + desc->obsolete_date = decode_uint16(p); + desc->axle_load = decode_uint16(p); + desc->wt = decode_uint8(p); + desc->styp = decode_uint8(p); + desc->overtaking_info = decode_sint8(p); //new + desc->draw_as_obj = decode_uint8(p); + desc->number_seasons = decode_sint8(p); + } + else if(version==6) { // version 6, now with axle load desc->cost = decode_uint32(p); desc->maintenance = decode_uint32(p); @@ -157,6 +173,10 @@ obj_desc_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node) desc->axle_load = 9999; } + if( version < 7 ) { + desc->overtaking_info = 1; + } + // front images from version 5 on desc->front_images = version > 4; diff --git a/descriptor/way_desc.h b/descriptor/way_desc.h index 4c586d4..fdcfc3c 100644 --- a/descriptor/way_desc.h +++ b/descriptor/way_desc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2002 by Volker Meyer & Hansjörg Malthaner + * Copyright (c) 1997 - 2002 by Volker Meyer & Hansj�rg Malthaner * * This file is part of the Simutrans project under the artistic licence. */ @@ -65,6 +65,12 @@ private: bool front_images; /** + * Overtaking info (0 = condition for one-way road, 1 = condition for two-way road, 2 = overtaking a loading convoy only, 3 = overtaking is completely forbidden) + * @author teamhimeH + */ + sint8 overtaking_info; + + /** * calculates index of image list for flat ways * for winter and/or front images * add +1 and +2 to get slope and straight diagonal images, respectively @@ -214,6 +220,10 @@ public: } void calc_checksum(checksum_t *chk) const; + + sint8 get_overtaking_info() const { + return overtaking_info; + } }; #endif diff --git a/descriptor/writer/way_writer.cc b/descriptor/writer/way_writer.cc index 5e0eb4a..26f6819 100644 --- a/descriptor/writer/way_writer.cc +++ b/descriptor/writer/way_writer.cc @@ -25,17 +25,18 @@ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) }; int ribi, hang; - obj_node_t node(this, 28, &parent); + obj_node_t node(this, 29, &parent); // Hajo: Version needs high bit set as trigger -> this is required // as marker because formerly nodes were unversionend - uint16 version = 0x8006; + uint16 version = 0x8007; uint32 price = obj.get_int("cost", 100); uint32 maintenance = obj.get_int("maintenance", 100); sint32 topspeed = obj.get_int("topspeed", 999); uint32 max_weight = obj.get_int("max_weight", 999); uint16 axle_load = obj.get_int("axle_load", 9999); + sint8 overtaking_info = obj.get_int("overtaking_info", 1); uint16 intro = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12; intro += obj.get_int("intro_month", 1) - 1; @@ -67,7 +68,8 @@ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) node.write_uint16(outfp, axle_load, 22); node.write_uint8 (outfp, wtyp, 24); node.write_uint8 (outfp, styp, 25); - node.write_uint8 (outfp, draw_as_ding, 26); + node.write_sint8 (outfp, overtaking_info, 26); + node.write_uint8 (outfp, draw_as_ding, 27); static const char* const image_type[] = { "", "front" }; @@ -76,7 +78,7 @@ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) sprintf(buf, "image[%s][0]", ribi_codes[0]); string str = obj.get(buf); if (str.empty()) { - node.write_data_at(outfp, &number_seasons, 27, 1); + node.write_data_at(outfp, &number_seasons, 28, 1); write_head(outfp, node, obj); sprintf(buf, "image[%s]", ribi_codes[0]); @@ -145,7 +147,7 @@ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj) number_seasons++; } - node.write_data_at(outfp, &number_seasons, 27, 1); + node.write_data_at(outfp, &number_seasons, 28, 1); write_head(outfp, node, obj); // has switch images for both directions? diff --git a/gui/onewaysign_info.cc b/gui/onewaysign_info.cc new file mode 100644 index 0000000..d1ef277 --- /dev/null +++ b/gui/onewaysign_info.cc @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1997 - 2003 Hansjörg Malthaner + * + * This file is part of the Simutrans project under the artistic licence. + * (see licence.txt) + */ + +#include "onewaysign_info.h" +#include "../obj/roadsign.h" +#include "../player/simplay.h" + + +#include "../simmenu.h" +#include "../simworld.h" + +onewaysign_info_t::onewaysign_info_t(roadsign_t* s, koord3d first_intersection) : + obj_infowin_t(s), + sign(s) +{ + direction[0].init( button_t::square_state, translator::translate("Left"), scr_coord(10,get_windowsize().h - 40), scr_size(40,D_BUTTON_HEIGHT) ); + direction[1].init( button_t::square_state, translator::translate("Right"), scr_coord(60,get_windowsize().h - 40), scr_size(40,D_BUTTON_HEIGHT) ); + direction[0].add_listener( this ); + direction[1].add_listener( this ); + direction[0].pressed = (sign->get_lane_fix() & 1) != 0; + direction[1].pressed = (sign->get_lane_fix() & 2) != 0; + add_component( &direction[0] ); + add_component( &direction[1] ); +} + + +/** + * This method is called if an action is triggered + * @author Hj. Malthaner + * + * Returns true, if action is done and no more + * components should be triggered. + * V.Meyer + */ +bool onewaysign_info_t::action_triggered( gui_action_creator_t *komp, value_t /* */) +{ + uint8 fix = sign->get_lane_fix(); + for( int i=0; i<2; i++ ) { + if(komp == &direction[i]) { + fix ^= (i+1); + } + } + sign->set_lane_fix(fix); + for( int i=0; i<2; i++ ) { + direction[i].pressed = (sign->get_lane_fix() & (i+1)) != 0; + } + return true; +} + + +// notify for an external update +void onewaysign_info_t::update_data() +{ + for( int i=0; i<2; i++ ) { + direction[i].pressed = (sign->get_lane_fix() & (i+1)) != 0; + } +} diff --git a/gui/onewaysign_info.h b/gui/onewaysign_info.h new file mode 100644 index 0000000..0b2aa42 --- /dev/null +++ b/gui/onewaysign_info.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 1997 - 2003 Hansjörg Malthaner + * + * This file is part of the Simutrans project under the artistic licence. + * (see licence.txt) + */ + +#ifndef onewaysign_info_t_h +#define onewaysign_info_t_h + +#include "../simconst.h" +#include "obj_info.h" +#include "components/action_listener.h" +#include "components/gui_button.h" +#include "components/gui_container.h" + +class roadsign_t; + +/** + * Info window for factories + * @author Hj. Malthaner + */ +class onewaysign_info_t : public obj_infowin_t, public action_listener_t +{ + private: + roadsign_t* sign; + button_t direction[2]; + + public: + onewaysign_info_t(roadsign_t* s, koord3d first_intersection); + + /** + * Set the window associated helptext + * @return the filename for the helptext, or NULL + * @author Hj. Malthaner + */ + const char *get_help_filename() const {return "onewaysign_info.txt";} + + bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE; + + // called, after external change + void update_data(); +}; + +#endif diff --git a/obj/roadsign.cc b/obj/roadsign.cc index 9637e1e..56d386e 100644 --- a/obj/roadsign.cc +++ b/obj/roadsign.cc @@ -32,6 +32,7 @@ #include "../gui/trafficlight_info.h" #include "../gui/privatesign_info.h" +#include "../gui/onewaysign_info.h" #include "../gui/tool_selector.h" #include "../tpl/stringhashtable_tpl.h" @@ -81,6 +82,7 @@ roadsign_t::roadsign_t(player_t *player, koord3d pos, ribi_t::ribi dir, const ro state = 0; ticks_ns = ticks_ow = 16; ticks_offset = 0; + lane_fix = 4; set_owner( player ); if( desc->is_private_way() ) { // init ownership of private ways @@ -172,6 +174,17 @@ void roadsign_t::show_info() else if( automatic ) { create_win(new trafficlight_info_t(this), w_info, (ptrdiff_t)this ); } + else if( desc->is_single_way() ) { + if( (intersection_pos = get_intersection()) == koord3d::invalid ) { + set_lane_fix(4); + obj_t::show_info(); + } + else { + // off the "not applied" bit flag + lane_fix = ~((~lane_fix)|4); + create_win(new onewaysign_info_t(this, intersection_pos), w_info, (ptrdiff_t)this ); + } + } else { obj_t::show_info(); } @@ -205,6 +218,9 @@ void roadsign_t::info(cbuffer_t & buf) const buf.append("\n"); buf.append("\n"); } + if(desc->is_single_way() && intersection_pos != koord3d::invalid) { + buf.printf("%s(%d,%d,%d)\n", translator::translate("intersection:"), intersection_pos.x,intersection_pos.y,intersection_pos.z); + } } } @@ -534,6 +550,14 @@ void roadsign_t::rdwr(loadsave_t *file) obj_t::rdwr(file); uint8 dummy=0; + if( file->get_version()>=120005 ) { + dummy = lane_fix; + file->rdwr_byte(dummy); + lane_fix = dummy; + } + else { + lane_fix = 4; // not applied + } if( file->get_version()<=102002 ) { file->rdwr_byte(dummy); if( file->is_loading() ) { @@ -725,3 +749,40 @@ const roadsign_desc_t *roadsign_t::roadsign_search(roadsign_desc_t::types const } return NULL; } + +const koord3d roadsign_t::get_intersection() const +{ + grund_t* current_gr = welt->lookup(get_pos()); + ribi_t::ribi current_ribi = ribi_t::reverse_single(dir); + for(int step = 0; step < 500; step++) { + grund_t *next_gr; + if( ribi_t::is_single(current_ribi) ) { + if( current_gr->get_neighbour(next_gr,road_wt,current_ribi) ) { + // grund found + //printf("(%d,%d)->(%d,%d), ribi:%d\n", current_gr->get_pos().x,current_gr->get_pos().y,next_gr->get_pos().x,next_gr->get_pos().y,current_ribi); + strasse_t *str = (strasse_t *)next_gr->get_weg(road_wt); + if( str && str->get_overtaking_info() == 0 ) { + ribi_t::ribi str_ribi = str->get_ribi(); + if( str_ribi == ribi_t::all || ribi_t::is_threeway(str_ribi) ) { + // This point is a crossing! + return next_gr->get_pos(); + } + else { + // go forward + current_gr = next_gr; + current_ribi = ~((~str_ribi)|ribi_t::reverse_single(current_ribi)); + } + } + else { + // there is no street or the street is not one-way road. + return koord3d::invalid; + } + } + else { + // grund not found + return koord3d::invalid; + } + } + } + return koord3d::invalid; +} diff --git a/obj/roadsign.h b/obj/roadsign.h index 65ea7bd..f7c2002 100644 --- a/obj/roadsign.h +++ b/obj/roadsign.h @@ -39,6 +39,10 @@ protected: sint8 after_yoffset, after_xoffset; + // 0 = not fixed, 1 = only fix left lane, 2 = only fix right lane, 3 = fix both lane, 4 = not applied + uint8 lane_fix; + koord3d intersection_pos; + const roadsign_desc_t *desc; ribi_t::ribi calc_mask() const { return ribi_t::is_single(dir) ? dir : (ribi_t::ribi)ribi_t::none; } @@ -114,6 +118,10 @@ public: inline void set_image( image_id b ) { image = b; } image_id get_image() const { return image; } + uint8 get_lane_fix() const { return lane_fix; } + void set_lane_fix(uint8 lf) { lane_fix = lf; } + const koord3d get_intersection() const; + /** * For the front image hiding vehicles * @author prissi diff --git a/simconvoi.cc b/simconvoi.cc index a8cf253..8bf42cd 100644 --- a/simconvoi.cc +++ b/simconvoi.cc @@ -1,9 +1,10 @@ /** * convoi_t Class for vehicle associations - * Hansjörg Malthaner + * Hansj�rg Malthaner */ #include +#include #include "simdebug.h" #include "simunits.h" @@ -31,6 +32,7 @@ #include "gui/convoi_detail_t.h" #include "boden/grund.h" #include "boden/wege/schiene.h" // for railblocks +#include "boden/wege/strasse.h" #include "descriptor/vehicle_desc.h" #include "descriptor/roadsign_desc.h" @@ -127,6 +129,8 @@ void convoi_t::init(player_t *player) wait_lock = 0; arrived_time = 0; + requested_change_lane = false; + jahresgewinn = 0; total_distance_traveled = 0; @@ -160,6 +164,8 @@ void convoi_t::init(player_t *player) line_update_pending = linehandle_t(); home_depot = koord3d::invalid; + yielding_quit_index = -1; + lane_fix = 0; recalc_data_front = true; recalc_data = true; @@ -728,6 +734,10 @@ void convoi_t::calc_acceleration(uint32 delta_t) sum_gesamtweight += total_vehicle_weight; } } + if( get_yielding_quit_index() != -1 && speed_limit > kmh_to_speed(15) ) { + //When yielding lane, speed_limit is 15 kmph lower. + speed_limit -= kmh_to_speed(15); + } recalc_data = recalc_speed_limit = false; akt_speed_soll = min( speed_limit, brake_speed_soll ); } @@ -991,7 +1001,7 @@ sync_result convoi_t::sync_step(uint32 delta_t) /** * Berechne route von Start- zu Zielkoordinate - * @author Hanjsörg Malthaner + * @author Hanjs�rg Malthaner */ bool convoi_t::drive_to() { @@ -1148,7 +1158,7 @@ bool convoi_t::drive_to() /** * Ein Fahrzeug hat ein Problem erkannt und erzwingt die * Berechnung einer neuen Route - * @author Hanjsörg Malthaner + * @author Hanjs�rg Malthaner */ void convoi_t::suche_neue_route() { @@ -1177,6 +1187,8 @@ void convoi_t::step() case LOADING: laden(); + //When loading, vehicle should not be on passing lane. + set_tiles_overtaking(0); break; case DUMMY4: @@ -1293,9 +1305,11 @@ void convoi_t::step() if(restart_speed>=0) { akt_speed = restart_speed; } + /* if(state==CAN_START || state==CAN_START_ONE_MONTH) { set_tiles_overtaking( 0 ); } + */ } break; @@ -1310,9 +1324,11 @@ void convoi_t::step() if(restart_speed>=0) { akt_speed = restart_speed; } + /* if(state!=DRIVING) { set_tiles_overtaking( 0 ); } + */ } break; @@ -2555,6 +2571,12 @@ void convoi_t::rdwr(loadsave_t *file) file->rdwr_short( next_reservation_index ); } + if( file->get_version()>=120005 ) { + file->rdwr_long(yielding_quit_index); + file->rdwr_byte(lane_fix); + file->rdwr_long(lane_fix_end_index); + } + if( file->is_loading() ) { reserve_route(); recalc_catg_index(); @@ -3573,11 +3595,27 @@ void convoi_t::set_withdraw(bool new_withdraw) */ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other) { - if(fahr[0]->get_waytype()!=road_wt) { + if( fahr[0]->get_waytype()!=road_wt ) { + return false; + } + 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; + } + sint8 overtaking_info = str->get_overtaking_info(); + if ( !other_overtaker->can_be_overtaken() && overtaking_info != 0 ) { return false; } - if (!other_overtaker->can_be_overtaken()) { + //Overtaking info (0 = condition for one-way road, 1 = condition for two-way road, 2 = overtaking a loading convoy only, 3 = overtaking is completely forbidden) + if( overtaking_info == 3 ){ + // This road prohibits overtaking. return false; } @@ -3585,18 +3623,9 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si /* 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(); + //TODO: This initialization of "tiles" should be considered again. 2 is not appropriate considering LC patch. 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 @@ -3616,23 +3645,27 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si if( str->is_crossing() ) { return false; } - if( ribi_t::is_threeway(str->get_ribi()) ) { + if( ribi_t::is_threeway(str->get_ribi()) && overtaking_info != 0 ) { + // On one-way road, overtaking on threeway is allowed. 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) { + if( overtaking_info != 0 ) { + // Check for other vehicles on the next tile + const uint8 top = gr->get_top(); + //These conditions is abandoned on one-way road to overtake in traffic jam. + 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; } } - else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { - return false; - } } } } @@ -3640,9 +3673,37 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si return true; } - int diff_speed = akt_speed - other_speed; - if( diff_speed < kmh_to_speed(5) ) { - return false; + // Around the end of route, overtaking moving convoi should not be allowed. + if( get_route()->get_count() - fahr[0]->get_route_index() < 5 ) { + return false; + } + // Do not overtake a vehicle which has higher max_power_speed than this. + if( other_overtaker->get_max_power_speed() - this->get_max_power_speed() > kmh_to_speed(5) ) { + return false; + } + + // The flag whether the convoi is in traffic jam. When this is true, we must calculate overtaking in a different way. + // On one-way road, other_speed is current speed. Otherwise, other_speed is the theoretical max power speed. + bool in_congestion = false; + int diff_speed = akt_speed - other_speed; + if( diff_speed < kmh_to_speed(5) ) { + // Overtaking in traffic jam is only accepted on one-way road. + if( overtaking_info == 0 ) { + grund_t *gr = welt->lookup(get_pos()); + strasse_t *str=(strasse_t *)gr->get_weg(road_wt); + if( str==NULL ) { + printf("street is NULL!\n"); + return false; + }else if( akt_speed < fmin(max_power_speed, str->get_max_speed())/2 && diff_speed >= kmh_to_speed(0) ){ + //Warning: diff_speed == 0 is acceptable. We must consider the case diff_speed == 0. + in_congestion = true; + }else{ + return false; + } + } + else { + return false; + } } // Number of tiles overtaking will take @@ -3651,10 +3712,17 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si // 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 - int distance = akt_speed*(fahr[0]->get_steps()+get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/diff_speed; + int distance = 1; + if( !in_congestion ) { + distance = akt_speed*(fahr[0]->get_steps()+get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/diff_speed; + } + else { + distance = max_power_speed*(fahr[0]->get_steps()+get_length_in_steps()+steps_other-VEHICLE_STEPS_PER_TILE)/(max_power_speed-other_speed); + } + int time_overtaking = 0; - // Conditions for overtaking: + // Conditions for overtaking (originally): // 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; @@ -3671,31 +3739,44 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si 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 ) { + if( gr==NULL ) { return false; } - weg_t *str = gr->get_weg(road_wt); if( str==NULL ) { return false; } + //Overtaking info (0 = condition for one-way road, 1 = condition for two-way road, 2 = overtaking a loading convoy only, 3 = overtaking is completely forbidden) + sint8 overtaking_info_loop = str->get_overtaking_info(); + if( overtaking_info_loop != 0 && gr->get_weg_hang() != slope_t::flat ) { + return false; + } + + if( overtaking_info_loop > 1 ){ + // Since the other vehicle is moving... + 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() ) { + if( rb->is_choose_sign() ) { // because we need to stop here ... return false; } + //We consider traffic-lights on two-way road. + if( rb->is_traffic_light() && overtaking_info_loop == 1 ) { + return false; + } } } // not overtaking on railroad crossings or on normal crossings ... - if( str->is_crossing() || ribi_t::is_threeway(str->get_ribi()) ) { + if( overtaking_info_loop == 1 && (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()) ) { + if( overtaking_info_loop == 1 && akt_speed > kmh_to_speed(str->get_max_speed()) ) { return false; } @@ -3711,7 +3792,17 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si const overtaker_t *ov = v->get_overtaker(); if(ov) { if(this!=ov && other_overtaker!=ov) { - return false; + if( overtaking_info_loop == 0 ) { + //If ov goes same directory, should not return false + ribi_t::ribi their_direction = ribi_t::backward( fahr[0]->calc_direction(pos_prev, pos_next) ); + vehicle_base_t* const v = obj_cast(gr->obj_bei(j)); + if (v && v->get_direction() == their_direction && v->get_overtaker()) { + return false; + } + } + else { + return false; + } } } else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) { @@ -3750,9 +3841,11 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si 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()); @@ -3774,8 +3867,11 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, sint32 other_speed, si pos = pos_next; } - set_tiles_overtaking( 1+n_tiles ); - other_overtaker->set_tiles_overtaking( -1-(n_tiles*(akt_speed-diff_speed))/akt_speed ); + set_tiles_overtaking( 2+n_tiles ); + //The parameter about being overtaken is no longer meaningful on one-way road. + if( overtaking_info != 0 ) { + other_overtaker->set_tiles_overtaking( -1-(n_tiles*(akt_speed-diff_speed))/akt_speed ); + } return true; } @@ -3845,3 +3941,78 @@ const char* convoi_t::send_to_depot(bool local) return txt; } + +/* + * Functions to yield lane space to vehicles on passing lane. + * More natural movement controll is desired! + * @author teamhimeH + */ +void convoi_t::yield_lane_space() +{ + if( speed_limit > kmh_to_speed(15) ) { + uint32 quit_index = fahr[0]->get_route_index() + 3u; + if( quit_index >= get_route()->get_count() ) { + quit_index = get_route()->get_count() - 1u; + } + yielding_quit_index = quit_index; + must_recalc_speed_limit(); + } +} + +bool convoi_t::calc_lane_fix(uint8 lane_fix_sign) +{ + if( lane_fix_sign!=0 && lane_fix_sign<4 ) { + uint16 test_index = fahr[0]->get_route_index(); + while( test_index < route.get_count() ) { + grund_t *gr = welt->lookup(route.at(test_index)); + if( !gr ) { + // way (weg) not existent (likely destroyed) + return false; + } + strasse_t *str = (strasse_t *)gr->get_weg(road_wt); + if( !str || gr->get_top() > 250 || str->get_overtaking_info() != 0 ) { + // too many cars here or no street or not one-way road + return false; + } + ribi_t::ribi str_ribi = str->get_ribi(); + if( str_ribi == ribi_t::all || ribi_t::is_threeway(str_ribi) ) { + // It's a intersection. + if( test_index == 0 || test_index == route.get_count() - 1 ) { + // cannot calculate prev_dir or next_dir + return false; + } + ribi_t::ribi prev_dir = vehicle_base_t::calc_direction(welt->lookup(route.at(test_index-1))->get_pos(),welt->lookup(route.at(test_index))->get_pos()); + ribi_t::ribi next_dir = vehicle_base_t::calc_direction(welt->lookup(route.at(test_index))->get_pos(),welt->lookup(route.at(test_index+1))->get_pos()); + ribi_t::ribi str_left = (ribi_t::rotate90l(prev_dir) & str_ribi) == 0 ? prev_dir : ribi_t::rotate90l(prev_dir); + ribi_t::ribi str_right = (ribi_t::rotate90(prev_dir) & str_ribi) == 0 ? prev_dir : ribi_t::rotate90(prev_dir); + if( next_dir == str_left && (lane_fix_sign & 1) != 0 ) { + // fix to left lane + if( welt->get_settings().is_drive_left() ) { + lane_fix = -1; + } + else { + lane_fix = 1; + } + lane_fix_end_index = test_index; + return true; + } + else if( next_dir == str_right && (lane_fix_sign & 2) != 0 ) { + // fix to right lane + if( welt->get_settings().is_drive_left() ) { + lane_fix = 1; + } + else { + lane_fix = -1; + } + lane_fix_end_index = test_index; + return true; + } + else { + return false; + } + } + test_index++; + } + } + return false; +} diff --git a/simconvoi.h b/simconvoi.h index eba6d9a..efe11fb 100644 --- a/simconvoi.h +++ b/simconvoi.h @@ -256,7 +256,7 @@ private: * The convoi is not processed every sync step for various actions * (like waiting before signals, loading etc.) Such action will only * continue after a waiting time larger than wait_lock - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ sint32 wait_lock; @@ -267,8 +267,14 @@ private: uint32 arrived_time; /** + *The flag whether this convoi is requested to change lane by the convoi behind this. + *@author teamhimeH + */ + bool requested_change_lane; + + /** * accumulated profit over a year - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ sint64 jahresgewinn; @@ -307,14 +313,14 @@ private: /** * Calculate route from Start to Target Coordinate - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ bool drive_to(); /** * Setup vehicles for moving in same direction than before * if the direction is the same as before - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ bool can_go_alte_richtung(); @@ -328,7 +334,7 @@ private: /** * Mark first and last vehicle. - * @author Hanjsörg Malthaner + * @author Hanjs�rg Malthaner */ void set_erstes_letztes(); @@ -397,6 +403,17 @@ private: uint32 move_to(uint16 start_index); + /** + * the route index of the point to quit yielding lane + * == -1 means this convoi isn't yielding. + * @author teamhimeH + */ + sint32 yielding_quit_index; + + // 0: not fixed, -1: fixed to traffic lane, 1:fixed to passing lane + sint8 lane_fix; + uint32 lane_fix_end_index; + public: /** * Convoi haelt an Haltestelle und setzt quote fuer Fracht @@ -462,13 +479,13 @@ public: /** * The handle for ourselves. In Anlehnung an 'this' aber mit * allen checks beim Zugriff. - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ convoihandle_t self; /** * The profit in this year - * @author Hanjsörg Malthaner + * @author Hanjs�rg Malthaner */ const sint64 & get_jahresgewinn() const {return jahresgewinn;} @@ -517,7 +534,7 @@ public: /** * Called if a vehicle enters a depot - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ void betrete_depot(depot_t *dep); @@ -622,7 +639,7 @@ public: /** * When a vehicle has detected a problem * force calculate a new route - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ void suche_neue_route(); @@ -739,7 +756,7 @@ public: /** * Setup vehicles before starting to move - * @author Hanjsörg Malthaner + * @author Hanjsörg Malthaner */ void vorfahren(); @@ -884,6 +901,25 @@ public: // Overtaking for convois virtual bool can_overtake(overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other); + + /* + * Functions related to requested_change_lane + * @author teamhimeH + */ + bool is_requested_change_lane() const { return requested_change_lane; } + void set_requested_change_lane(bool x) { requested_change_lane = x; } + void yield_lane_space(); + sint32 get_yielding_quit_index() const { return yielding_quit_index; } + void quit_yielding_lane() { yielding_quit_index = -1; must_recalc_speed_limit(); } + + /* + * Functions related to lane fixing + * @author teamhimeH + */ + bool calc_lane_fix(uint8 lane_fix_sign); // If true, lane fixing started. + uint32 get_lane_fix_end_index() const { return lane_fix_end_index; } + sint8 get_lane_fix() const { return lane_fix; } + void reset_lane_fix() { lane_fix = 0; } }; #endif diff --git a/simversion.h b/simversion.h index 5777151..967961f 100644 --- a/simversion.h +++ b/simversion.h @@ -17,8 +17,8 @@ // Beware: SAVEGAME minor is often ahead of version minor when there were patches. // ==> These have no direct connection at all! -#define SIM_SAVE_MINOR 4 -#define SIM_SERVER_MINOR 4 +#define SIM_SAVE_MINOR 5 +#define SIM_SERVER_MINOR 5 // NOTE: increment before next release to enable save/load of new features #define MAKEOBJ_VERSION "60.0" diff --git a/utils/dr_rdpng.cc b/utils/dr_rdpng.cc index d17bfdc..841da5b 100644 --- a/utils/dr_rdpng.cc +++ b/utils/dr_rdpng.cc @@ -1,6 +1,7 @@ #include -#include +//#include +#include "/opt/local/include/libpng16/png.h" #include #include #include diff --git a/vehicle/overtaker.h b/vehicle/overtaker.h index 14b0e69..8c3248e 100644 --- a/vehicle/overtaker.h +++ b/vehicle/overtaker.h @@ -60,6 +60,8 @@ 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; } + + sint8 get_tiles_overtaking() const { return tiles_overtaking; } }; #endif diff --git a/vehicle/simvehicle.cc b/vehicle/simvehicle.cc index 1e89837..7f12dfa 100644 --- a/vehicle/simvehicle.cc +++ b/vehicle/simvehicle.cc @@ -131,6 +131,8 @@ sint8 vehicle_base_t::driveleft_base_offsets[8][2] = // [0]=xoff [1]=yoff sint8 vehicle_base_t::overtaking_base_offsets[8][2]; +bool vehicle_base_t::left_driving = false; + // recalc offsets for overtaking void vehicle_base_t::set_overtaking_offsets( bool driving_on_the_left ) { @@ -156,6 +158,8 @@ void vehicle_base_t::set_overtaking_offsets( bool driving_on_the_left ) overtaking_base_offsets[5][1] = -sign * YOFF; overtaking_base_offsets[6][1] = -sign * YOFF; overtaking_base_offsets[7][1] = 0; + + left_driving = driving_on_the_left; } @@ -526,6 +530,9 @@ sint8 vehicle_base_t::get_hoff() const */ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convoi_t *cnv, const uint8 current_direction, const uint8 next_direction, const uint8 next_90direction ) { + bool cnv_overtaking = false; //whether this convoi is on passing lane. + if( cnv ) cnv_overtaking = cnv -> is_overtaking(); + if( next_enter_passing_lane ) cnv_overtaking = true; //treated as convoi is overtaking. // Search vehicle for( uint8 pos=1; pos<(volatile uint8)gr->get_top(); pos++ ) { if( vehicle_base_t* const v = obj_cast(gr->obj_bei(pos)) ) { @@ -536,6 +543,7 @@ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convo // check for car uint8 other_direction=255; bool other_moving = false; + bool other_overtaking = false; //whether the other convoi is on passing lane. if( road_vehicle_t const* const at = obj_cast(v) ) { // ignore ourself if( cnv == at->get_convoi() ) { @@ -543,24 +551,28 @@ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convo } other_direction = at->get_direction(); other_moving = at->get_convoi()->get_akt_speed() > kmh_to_speed(1); + other_overtaking = at->get_convoi()->is_overtaking(); } // check for city car else if( v->get_waytype() == road_wt ) { other_direction = v->get_direction(); if( private_car_t const* const sa = obj_cast(v) ){ other_moving = sa->get_current_speed() > 1; + other_overtaking = sa->is_overtaking(); } } // ok, there is another car ... if( other_direction != 255 ) { - if( next_direction == other_direction && !ribi_t::is_threeway(gr->get_weg_ribi(road_wt)) ) { + if( next_direction == other_direction && !ribi_t::is_threeway(gr->get_weg_ribi(road_wt)) && cnv_overtaking == other_overtaking ) { + // only consider cars on same lane. // cars going in the same direction and no crossing => that mean blocking ... return v; } const ribi_t::ribi other_90direction = (gr->get_pos().get_2d() == v->get_pos_next().get_2d()) ? other_direction : calc_direction(gr->get_pos(), v->get_pos_next()); - if( other_90direction == next_90direction ) { + if( other_90direction == next_90direction && cnv_overtaking == other_overtaking ) { + //Whether this code is safe is not clear!!(can ignore cars on the other lane?) // Want to exit in same as other ~50% of the time return v; } @@ -568,7 +580,8 @@ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convo const bool drives_on_left = welt->get_settings().is_drive_left(); const bool across = next_direction == (drives_on_left ? ribi_t::rotate45l(next_90direction) : ribi_t::rotate45(next_90direction)); // turning across the opposite directions lane const bool other_across = other_direction == (drives_on_left ? ribi_t::rotate45l(other_90direction) : ribi_t::rotate45(other_90direction)); // other is turning across the opposite directions lane - if( other_direction == next_direction && !(other_across || across) ) { + if( other_direction == next_direction && !(other_across || across) && cnv_overtaking == other_overtaking) { + // only consider cars on same lane. // entering same straight waypoint as other ~18% return v; } @@ -590,6 +603,7 @@ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convo return v; } else if( other_direction == current_direction && current_90direction == ribi_t::none ) { + // !It is not clear whether we should consider opposite lane in this case! // entering same diagonal waypoint as other ~1% return v; } @@ -603,6 +617,59 @@ vehicle_base_t *vehicle_base_t::no_cars_blocking( const grund_t *gr, const convo return NULL; } +bool vehicle_base_t::judge_lane_crossing( const uint8 current_direction, const uint8 next_direction, const uint8 other_next_direction, const bool is_overtaking, const bool forced_to_change_lane ) +{ + bool on_left = false; + if( is_overtaking && !left_driving ) { + on_left = true; + } + if( !is_overtaking && left_driving ) { + on_left = true; + } + // go straight = 0, turn right = -1, turn left = 1. + sint8 this_turn; + if( next_direction == ribi_t::rotate90(current_direction) ) { + this_turn = -1; + } + else if( next_direction == ribi_t::rotate90l(current_direction) ) { + this_turn = 1; + } + else { + // go straight? + this_turn = 0; + } + sint8 other_turn; + if( other_next_direction == ribi_t::rotate90(current_direction) ) { + other_turn = -1; + } + else if( other_next_direction == ribi_t::rotate90l(current_direction) ) { + other_turn = 1; + } + else { + // go straight? + other_turn = 0; + } + if( on_left ) { + if( forced_to_change_lane && other_turn - this_turn >= 0 ) { + //printf("current:%d, next:%d, other:%d\n", current_direction,next_direction,other_next_direction); + //printf("on left: %d,%d (%d,%d)\n", this_turn, other_turn, get_pos().x, get_pos().y); + return true; + } + else if( other_turn - this_turn > 0 ) { + return true; + } + } + else { + if( forced_to_change_lane && other_turn - this_turn <= 0 ) { + //printf("on right: %d,%d (%d,%d)\n", this_turn, other_turn, get_pos().x, get_pos().y); + return true; + } + else if( other_turn - this_turn < 0 ) { + return true; + } + } + return false; +} void vehicle_t::rotate90() { @@ -1699,6 +1766,14 @@ const char *vehicle_t::is_deletable(const player_t *) return "Fahrzeuge koennen so nicht entfernt werden"; } +ribi_t::ribi vehicle_t::get_next_90direction() const { + const route_t* route = cnv->get_route(); + if( route && route_index < route->get_count() - 1u ) { + const koord3d pos_next2 = route->at(route_index + 1u); + return calc_direction(pos_next,pos_next2); + } + return ribi_t::none; +} vehicle_t::~vehicle_t() { @@ -2114,13 +2189,30 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui } } + route_t const& r = *cnv->get_route(); + + // At a crossing, decide whether the convoi should go on passing lane. + // side road -> main road from passing lane side: vehicle should enter passing lane on main road. + next_enter_passing_lane = false; + if( (str->get_ribi_unmasked() == ribi_t::all || ribi_t::is_threeway(str->get_ribi_unmasked())) && str->get_overtaking_info() == 0 ) { + const strasse_t* str_prev = route_index == 0 ? NULL : (strasse_t *)welt->lookup(r.at(route_index - 1u))->get_weg(road_wt); + const strasse_t* str_next = route_index < r.get_count() - 1u ? (strasse_t *)welt->lookup(r.at(route_index + 1u))->get_weg(road_wt) : NULL; + if(str_prev && str_next && str_prev->get_overtaking_info() > 0 && str_next->get_overtaking_info() == 0) { + const koord3d pos_next2 = route_index < r.get_count() - 1u ? r.at(route_index + 1u) : pos_next; + if( (!left_driving && ribi_t::rotate90l(get_90direction()) == calc_direction(pos_next,pos_next2)) || (left_driving && ribi_t::rotate90(get_90direction()) == calc_direction(pos_next,pos_next2)) ) { + // next: enter passing lane. + next_enter_passing_lane = true; + } + } + } + vehicle_base_t *obj = NULL; uint32 test_index = route_index + 1u; // way should be clear for overtaking: we checked previously - if( !cnv->is_overtaking() ) { + // Now we have to consider even if convoi is overtaking! + //if( !cnv->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; ribi_t::ribi curr_direction = get_direction(); ribi_t::ribi curr_90direction = calc_direction(get_pos(), pos_next); @@ -2132,6 +2224,43 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui const bool drives_on_left = welt->get_settings().is_drive_left(); bool int_block = ribi_t::is_threeway(str->get_ribi_unmasked()) && (((drives_on_left ? ribi_t::rotate90l(curr_90direction) : ribi_t::rotate90(curr_90direction)) & str->get_ribi_unmasked()) || curr_90direction != next_90direction || (rs && rs->get_desc()->is_traffic_light())); + //If this convoi is overtaking, the convoi must avoid a head-on crash. + if( cnv->is_overtaking() ){ + while( test_index < route_index + 4u && test_index < r.get_count() ){ + grund_t *grn = welt->lookup(r.at(test_index)); + for( uint8 pos=1; pos<(volatile uint8)grn->get_top(); pos++ ){ + if( vehicle_base_t* const v = obj_cast(grn->obj_bei(pos)) ){ + if( v->get_typ()==obj_t::pedestrian ) { + continue; + } + ribi_t::ribi other_direction=255; + if( road_vehicle_t const* const at = obj_cast(v) ) { + //ignore ourself + if( cnv == at->get_convoi() ){ + continue; + } + other_direction = at->get_direction(); + } + //check for city car + else if( v->get_waytype() == road_wt ) { + other_direction = v->get_direction(); + } + if( other_direction != 255 ){ + //There is another car. We have to check if this convoi is facing or not. + //calc_direction(next,get_pos()):opposite direction of next_direction. + if( calc_direction(next,get_pos()) == other_direction ) { + //printf("crash avoid. (%d,%d)\n", get_pos().x, get_pos().y); + cnv->set_tiles_overtaking(0); + } + } + } + } + test_index++; + } + } + + test_index = route_index + 1u;//reset test_index + // check exit from crossings and intersections, allow to proceed after 4 consecutive while( !obj && (str->is_crossing() || int_block) && test_index < r.get_count() && test_index < route_index + 4u ) { if( str->is_crossing() ) { @@ -2227,42 +2356,191 @@ bool road_vehicle_t::can_enter_tile(const grund_t *gr, sint32 &restart_speed, ui } } } - } + //} // stuck message ... if( obj && !second_check_count ) { - 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); - cnv->reset_waiting(); - } - else { + // Process is different whether the road is for one-way or two-way + sint8 overtaking_info = str->get_overtaking_info(); + if( overtaking_info == 0 ) { + // road is one-way. if( test_index == route_index + 1u ) { // no intersections or crossings, we might be able to overtake this one ... overtaker_t *over = obj->get_overtaker(); - if( over && !over->is_overtaken() ) { - if( over->is_overtaking() ) { - // otherwise we would stop every time being overtaken - return true; - } + if( over ) { // 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()) ) { + // yielding vehicle should not be overtaken by the vehicle whose maximum speed is same. + bool yielding_factor = true; + if( ocnv->get_yielding_quit_index() != -1 && this->get_speed_limit() - ocnv->get_speed_limit() < kmh_to_speed(10) ) { + yielding_factor = false; + } + if( cnv->get_lane_fix() != -1 && !next_enter_passing_lane && !cnv->is_overtaking() && !other_lane_blocked() && yielding_factor && cnv->can_overtake( ocnv, (ocnv->get_state()==convoi_t::LOADING ? 0 : ocnv->get_akt_speed()), ocnv->get_length_in_steps()+ocnv->get_vehikel(0)->get_steps()) ) { return true; } + strasse_t *str=(strasse_t *)gr->get_weg(road_wt); + sint32 cnv_max_speed = (int)fmin(cnv->get_speed_limit(), str->get_max_speed()*kmh_to_speed(1)); + sint32 other_max_speed = (int)fmin(ocnv->get_speed_limit(), str->get_max_speed()*kmh_to_speed(1)); + //printf("cnv=%d, other=%d, str=%d (%d,%d)\n", cnv_max_speed/kmh_to_speed(1),other_max_speed/kmh_to_speed(1),str->get_max_speed(), get_pos().x, get_pos().y); + if( cnv->is_overtaking() && kmh_to_speed(10) < cnv_max_speed - other_max_speed ) { + //If the convoi is on passing lane and there is slower convoi in front of this, this convoi request the slower to go to traffic lane. + ocnv->set_requested_change_lane(true); + } + //For the case that the faster convoi is on traffic lane. + if( cnv->get_lane_fix() != -1 && !next_enter_passing_lane && !cnv->is_overtaking() && kmh_to_speed(10) < cnv_max_speed - other_max_speed ) { + if( vehicle_base_t* const br = car->other_lane_blocked() ) { + if( road_vehicle_t const* const blk = obj_cast(br) ) { + if( car->get_direction() == blk->get_direction() && abs(car->get_convoi()->get_speed_limit() - blk->get_convoi()->get_speed_limit()) < kmh_to_speed(5) ){ + //same direction && (almost) same speed vehicle exists. + ocnv->yield_lane_space(); + } + } + } + } } else if( private_car_t* const caut = obj_cast(obj) ) { - if( cnv->can_overtake(caut, caut->get_desc()->get_geschw(), VEHICLE_STEPS_PER_TILE) ) { + if( cnv->get_lane_fix() != -1 && !next_enter_passing_lane && !cnv->is_overtaking() && !other_lane_blocked() && cnv->can_overtake(caut, caut->get_desc()->get_geschw(), VEHICLE_STEPS_PER_TILE) ) { return true; } } } } // we have to wait ... - restart_speed = (cnv->get_akt_speed()*3)/4; - cnv->set_tiles_overtaking(0); + if( obj->is_stuck() ) { + // end of traffic jam, but no stuck message, because previous vehicle is stuck too + restart_speed = 0; + cnv->reset_waiting(); + if( cnv->is_overtaking() && other_lane_blocked() == NULL ) { + cnv->set_tiles_overtaking(0); + } + } + else { + restart_speed = (cnv->get_akt_speed()*3)/4; + } + } + else if( overtaking_info <= 2 ) { + // road is two-way and overtaking is allowed on the stricter condition. + 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); + cnv->reset_waiting(); + } + else { + if( test_index == route_index + 1u ) { + // no intersections or crossings, we might be able to overtake this one ... + overtaker_t *over = obj->get_overtaker(); + if( over && !over->is_overtaken() ) { + if( over->is_overtaking() ) { + // otherwise we would stop every time being overtaken + return true; + } + // 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()) ) { + return true; + } + } + else if( private_car_t* const caut = obj_cast(obj) ) { + if( cnv->can_overtake(caut, caut->get_desc()->get_geschw(), VEHICLE_STEPS_PER_TILE) ) { + return true; + } + } + } + } + // we have to wait ... + restart_speed = (cnv->get_akt_speed()*3)/4; + //cnv->set_tiles_overtaking(0); + } + } + else { + // lane change is prohibited. + 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); + cnv->reset_waiting(); + } + else { + // we have to wait ... + restart_speed = (cnv->get_akt_speed()*3)/4; + //cnv->set_tiles_overtaking(0); + } + } + } + + const koord3d pos_next2 = route_index < r.get_count() - 1u ? r.at(route_index + 1u) : pos_next; + const koord3d pos_next3 = route_index < r.get_count() - 2u ? r.at(route_index + 2u) : pos_next2; + // If this vehicle is on passing lane and the next tile prohibites overtaking, this vehicle must wait until traffic lane become safe. + if( cnv->is_overtaking() && str->get_overtaking_info() == 3 ) { + // TODO:other_lane_blocked() method is inappropriate for the condition. + if( vehicle_base_t* v = other_lane_blocked() ) { + if( v->get_waytype() == road_wt && judge_lane_crossing(get_90direction(), calc_direction(pos_next,pos_next2), v->get_90direction(), true, true)) { + restart_speed = 0; + cnv->reset_waiting(); + return false; + } + } + // There is no vehicle on traffic lane. + cnv->set_tiles_overtaking(0); + return true; + } + // If this vehicle is on traffic lane and the next tile forces to go passing lane, this vehicle must wait until passing lane become safe. + if( !cnv->is_overtaking() && str->get_overtaking_info() == 4 ) { + if( vehicle_base_t* v = other_lane_blocked() ) { + if( v->get_waytype() == road_wt && judge_lane_crossing(get_90direction(), calc_direction(pos_next,pos_next2), v->get_90direction(), false, true)) { + restart_speed = 0; + cnv->reset_waiting(); + return false; + } + } + // There is no vehicle on passing lane. + next_enter_passing_lane = true; + return true; + } + // If this vehicle is forced to go back to traffic lane at the next tile and traffic lane is not safe to change lane, this vehicle should wait. + if( str->get_overtaking_info() > 0 && str->get_overtaking_info() < 4 && cnv->get_tiles_overtaking() == 1 ) { + if( vehicle_base_t* v = other_lane_blocked() ) { + if( v->get_waytype() == road_wt && judge_lane_crossing(get_90direction(), calc_direction(pos_next,pos_next2), v->get_90direction(), true, true)) { + restart_speed = 0; + cnv->reset_waiting(); + return false; + } + } + } + // If 2 tiles ahead is a crossing, lane crossing must be checked before entering. + // strasse_t *str=(strasse_t *)gr->get_weg(road_wt); + const grund_t *gr = route_index < r.get_count() - 1u ? welt->lookup(r.at(route_index+1u)) : NULL; + const strasse_t *stre= gr ? (strasse_t *)gr->get_weg(road_wt) : NULL; + const ribi_t::ribi way_ribi = stre ? stre->get_ribi_unmasked() : ribi_t::none; + if( stre && stre->get_overtaking_info() == 0 && (way_ribi == ribi_t::all || ribi_t::is_threeway(way_ribi)) ) { + if( const vehicle_base_t* v = other_lane_blocked(true) ) { + if( road_vehicle_t const* const at = obj_cast(v) ) { + if( judge_lane_crossing(calc_direction(pos_next,pos_next2), calc_direction(pos_next2,pos_next3), at->get_next_90direction(), cnv->is_overtaking(), false) ) { + // vehicle must stop. + restart_speed = 0; + cnv->reset_waiting(); + return false; + } + } + } + } + // For the case that this vehicle is fixed to passing lane and is on traffic lane. + if( str->get_overtaking_info() == 0 && cnv->get_lane_fix() == 1 && !cnv->is_overtaking() ) { + if( vehicle_base_t* v = other_lane_blocked() ) { + if( road_vehicle_t const* const car = obj_cast(v) ) { + convoi_t* ocnv = car->get_convoi(); + if( ocnv && abs(cnv->get_speed_limit() - ocnv->get_speed_limit()) < kmh_to_speed(5) ) { + cnv->yield_lane_space(); + } + } + // TODO: for citycar + } + else { + // go on passing lane. + cnv->set_tiles_overtaking(3); } } @@ -2278,6 +2556,58 @@ overtaker_t* road_vehicle_t::get_overtaker() return cnv; } +//return overtaker in "convoi_t" +convoi_t* road_vehicle_t::get_overtaker_cv() +{ + return cnv; +} + +vehicle_base_t* road_vehicle_t::other_lane_blocked(const bool only_search_top) const{ + //This function calculate whether the convoi can change lane. + //TODO: This function haven't considered city car! + if( leading ){ + route_t const& r = *cnv->get_route(); + // only_search_top == false: check whether there's no car in -1 ~ +1 section. + // only_search_top == true: check whether there's no car in front of this vehicle. (Not the same lane.) + for(uint32 test_index = route_index < r.get_count() ? route_index : r.get_count() - 1u; test_index >= route_index - 2u; test_index--){ + grund_t *gr = welt->lookup(r.at(test_index)); + for( uint8 pos=1; pos<(volatile uint8)gr->get_top(); pos++ ) { + if( vehicle_base_t* const v = obj_cast(gr->obj_bei(pos)) ) { + if( v->get_typ()==obj_t::pedestrian ) { + continue; + } + if( road_vehicle_t const* const at = obj_cast(v) ) { + // ignore ourself + if( cnv == at->get_convoi() ) { + continue; + } + if( cnv->is_overtaking() && at->get_convoi()->is_overtaking() ){ + continue; + } + if( !cnv->is_overtaking() && !(at->get_convoi()->is_overtaking()) ){ + //Prohibit going on passing lane when facing traffic exists. + ribi_t::ribi other_direction = at->get_direction(); + route_t const& r = *cnv->get_route(); + koord3d next = route_index < r.get_count() - 1u ? r.at(route_index + 1u) : pos_next; + if( calc_direction(next,get_pos()) == other_direction ) { + return v; + } + continue; + } + if( test_index == route_index - 2u && at->get_convoi()->get_akt_speed() == 0 ) { + continue; + } + return v; + } + } + } + if( test_index == 0 || only_search_top ) { + break; + } + } + } + return NULL; +} void road_vehicle_t::enter_tile(grund_t* gr) { @@ -2286,9 +2616,56 @@ void road_vehicle_t::enter_tile(grund_t* gr) const int cargo = get_total_cargo(); weg_t *str = gr->get_weg(road_wt); str->book(cargo, WAY_STAT_GOODS); - if (leading) { + if ( leading ) { str->book(1, WAY_STAT_CONVOIS); cnv->update_tiles_overtaking(); + if( next_enter_passing_lane ) { + cnv->set_tiles_overtaking(3); + next_enter_passing_lane = false; + } + //decide if overtaking convoi should go back to the traffic lane. + if( cnv->get_tiles_overtaking() == 1 && str->get_overtaking_info() == 0 ){ + vehicle_base_t* v = NULL; + if( cnv->get_lane_fix() == 1 || (v = other_lane_blocked())!=NULL ){ + //lane change denied + cnv->set_tiles_overtaking(3); + if( cnv->is_requested_change_lane() || cnv->get_lane_fix() == -1 ) { + //request the blocking convoi to reduce speed. + if( v ) { + if( road_vehicle_t const* const car = obj_cast(v) ) { + if( abs(cnv->get_speed_limit() - car->get_convoi()->get_speed_limit()) < kmh_to_speed(5) ) { + car->get_convoi()->yield_lane_space(); + } + } + } + else { + // perhaps this vehicle is in lane fixing. + cnv->set_requested_change_lane(false); + } + } + } + else { + //lane change accepted + cnv->set_requested_change_lane(false); + } + } + if( cnv->get_yielding_quit_index() == route_index ) { + cnv->quit_yielding_lane(); + } + if( str->get_overtaking_info() == 4 ) { + cnv->set_tiles_overtaking(1); + } + // If there is one-way sign, calc lane_fix. This should not be calculated in can_enter_tile(). + if( roadsign_t* rs = gr->find() ) { + if( rs->get_desc()->is_single_way() ) { + if( cnv->calc_lane_fix(rs->get_lane_fix()) ) { + // write debug code here. + } + } + } + if( cnv->get_lane_fix_end_index() == route_index ) { + cnv->reset_lane_fix(); + } } } diff --git a/vehicle/simvehicle.h b/vehicle/simvehicle.h index 9fe907e..7971a0a 100644 --- a/vehicle/simvehicle.h +++ b/vehicle/simvehicle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001 Hansjörg Malthaner + * Copyright (c) 1997 - 2001 Hansjörg Malthaner * * This file is part of the Simutrans project under the artistic license. * (see license.txt) @@ -52,6 +52,9 @@ protected: static sint8 driveleft_base_offsets[8][2]; static sint8 overtaking_base_offsets[8][2]; + // right side driving or left side driving? + static bool left_driving; + /** * Actual travel direction in screen coordinates * @author Hj. Malthaner @@ -82,6 +85,9 @@ protected: // cached image image_id image; + // true, if this vehicle will enter passing lane in the next tile + bool next_enter_passing_lane; + /** * Vehicle movement: check whether this vehicle can enter the next tile (pos_next). * @returns NULL if check fails, otherwise pointer to the next tile @@ -99,6 +105,9 @@ protected: // check for road vehicle, if next tile is free vehicle_base_t *no_cars_blocking( const grund_t *gr, const convoi_t *cnv, const uint8 current_direction, const uint8 next_direction, const uint8 next_90direction ); + // If true, two vehicles might crash by lane crossing. + bool judge_lane_crossing( const uint8 current_direction, const uint8 next_direction, const uint8 other_next_direction, const bool is_overtaking, const bool forced_to_change_lane ); + // only needed for old way of moving vehicles to determine position at loading time bool is_about_to_hop( const sint8 neu_xoff, const sint8 neu_yoff ) const; @@ -144,6 +153,8 @@ public: ribi_t::ribi get_direction() const {return direction;} + ribi_t::ribi get_90direction() const {return ribi_type(get_pos(), get_pos_next());} + koord3d get_pos_next() const {return pos_next;} virtual waytype_t get_waytype() const = 0; @@ -164,6 +175,7 @@ public: virtual void leave_tile(); virtual overtaker_t *get_overtaker() { return NULL; } + virtual convoi_t* get_overtaker_cv() { return NULL; } vehicle_base_t(); @@ -380,6 +392,8 @@ public: */ uint16 get_cargo_max() const {return desc->get_capacity(); } + ribi_t::ribi get_next_90direction() const; + const char * get_cargo_mass() const; /** @@ -513,6 +527,10 @@ public: schedule_t * generate_new_schedule() const; virtual overtaker_t* get_overtaker(); + virtual convoi_t* get_overtaker_cv(); + + virtual vehicle_base_t* other_lane_blocked() const { return other_lane_blocked(false); } + virtual vehicle_base_t* other_lane_blocked(const bool only_search_top) const; };