1 /**
2 * Moving objects for Simutrans.
3 * Transport vehicles are defined in simvehicle.h, because they greatly
4 * differ from the vehicles defined herein for the individual traffic
5 * (pedestrians, citycars, movingobj aka flock of sheep).
6 *
7 * Hj. Malthaner
8 *
9 * April 2000
10 */
11
12 #include "../simdebug.h"
13 #include "../display/simgraph.h"
14 #include "../simmesg.h"
15 #include "../simworld.h"
16 #include "../utils/simrandom.h"
17 #include "../display/simimg.h"
18 #include "../simunits.h"
19 #include "../simtypes.h"
20 #include "../simconvoi.h"
21
22 #include "simroadtraffic.h"
23 #ifdef DESTINATION_CITYCARS
24 // for final citycar destinations
25 #include "simpeople.h"
26 #endif
27
28 #include "../dataobj/translator.h"
29 #include "../dataobj/loadsave.h"
30 #include "../dataobj/environment.h"
31
32 #include "../obj/crossing.h"
33 #include "../obj/roadsign.h"
34
35 #include "../boden/grund.h"
36 #include "../boden/wege/weg.h"
37
38 #include "../descriptor/citycar_desc.h"
39 #include "../descriptor/roadsign_desc.h"
40
41
42 #include "../utils/cbuffer_t.h"
43
44 /**********************************************************************************************************************/
45 /* Road users (private cars and pedestrians) basis class from here on */
46
47
road_user_t()48 road_user_t::road_user_t() :
49 vehicle_base_t()
50 {
51 set_owner( welt->get_public_player() );
52 time_to_life = 0;
53 weg_next = 0;
54 }
55
56
57 /**
58 * Ensures that this object is removed correctly from the list
59 * of sync step-able things!
60 * @author Hj. Malthaner
61 */
~road_user_t()62 road_user_t::~road_user_t()
63 {
64 mark_image_dirty( get_image(), 0 );
65 }
66
67
road_user_t(grund_t * bd,uint16 random)68 road_user_t::road_user_t(grund_t* bd, uint16 random) :
69 vehicle_base_t(bd ? bd->get_pos() : koord3d::invalid)
70 {
71 ribi_t::ribi road_ribi = bd->get_weg_ribi(road_wt);
72
73 weg_next = random;
74
75 // randomized offset
76 uint8 offset = random & 3;
77 direction = ribi_t::nsew[offset];
78
79 grund_t *to = NULL;
80 for(uint8 r = 0; r < 4; r++) {
81 ribi_t::ribi ribi = ribi_t::nsew[ (r + offset) &3];
82 if( (ribi & road_ribi)!=0 && bd->get_neighbour(to, road_wt, ribi)) {
83 direction = ribi;
84 break;
85 }
86 }
87
88 switch(direction) {
89 case ribi_t::north:
90 dx = 2;
91 dy = -1;
92 break;
93 case ribi_t::south:
94 dx = -2;
95 dy = 1;
96 break;
97 case ribi_t::east:
98 dx = 2;
99 dy = 1;
100 break;
101 case ribi_t::west:
102 dx = -2;
103 dy = -1;
104 break;
105 }
106
107 set_xoff( (dx<0) ? OBJECT_OFFSET_STEPS : -OBJECT_OFFSET_STEPS );
108 set_yoff( (dy<0) ? OBJECT_OFFSET_STEPS/2 : -OBJECT_OFFSET_STEPS/2 );
109
110 if(to) {
111 pos_next = to->get_pos();
112 }
113 else {
114 pos_next = welt->lookup_kartenboden(get_pos().get_2d() + koord(direction))->get_pos();
115 }
116 set_owner( welt->get_public_player() );
117 }
118
119
120 /**
121 * Open a new observation window for the object.
122 * @author Hj. Malthaner
123 */
show_info()124 void road_user_t::show_info()
125 {
126 if(env_t::road_user_info) {
127 obj_t::show_info();
128 }
129 }
130
131
rdwr(loadsave_t * file)132 void road_user_t::rdwr(loadsave_t *file)
133 {
134 xml_tag_t t( file, "verkehrsteilnehmer_t" );
135
136 sint8 hoff = file->is_saving() ? get_hoff() : 0;
137
138 // correct old offsets ... REMOVE after savegame increase ...
139 if(file->is_version_less(99, 18) && file->is_saving()) {
140 dx = dxdy[ ribi_t::get_dir(direction)*2 ];
141 dy = dxdy[ ribi_t::get_dir(direction)*2+1 ];
142 sint8 i = steps/16;
143 set_xoff( get_xoff() + i*dx );
144 set_yoff( get_yoff() + i*dy + hoff );
145 }
146
147 vehicle_base_t::rdwr(file);
148
149 if(file->is_version_less(86, 6)) {
150 sint32 l;
151 file->rdwr_long(l);
152 file->rdwr_long(l);
153 file->rdwr_long(weg_next);
154 file->rdwr_long(l);
155 dx = (sint8)l;
156 file->rdwr_long(l);
157 dy = (sint8)l;
158 file->rdwr_enum(direction);
159 file->rdwr_long(l);
160 hoff = (sint8)l;
161 }
162 else {
163 if(file->is_version_less(99, 5)) {
164 sint32 dummy32;
165 file->rdwr_long(dummy32);
166 }
167 file->rdwr_long(weg_next);
168 if(file->is_version_less(99, 18)) {
169 file->rdwr_byte(dx);
170 file->rdwr_byte(dy);
171 }
172 else {
173 file->rdwr_byte(steps);
174 file->rdwr_byte(steps_next);
175 }
176 file->rdwr_enum(direction);
177 dx = dxdy[ ribi_t::get_dir(direction)*2];
178 dy = dxdy[ ribi_t::get_dir(direction)*2+1];
179 if(file->is_version_less(99, 5) || file->is_version_atleast(99, 17)) {
180 sint16 dummy16 = ((16*(sint16)hoff)/OBJECT_OFFSET_STEPS);
181 file->rdwr_short(dummy16);
182 hoff = (sint8)((OBJECT_OFFSET_STEPS*(sint16)dummy16)/16);
183 }
184 else {
185 file->rdwr_byte(hoff);
186 }
187 }
188 pos_next.rdwr(file);
189
190 // convert steps to position
191 if(file->is_version_less(99, 18)) {
192 sint8 ddx=get_xoff(), ddy=get_yoff()-hoff;
193 sint8 i=0;
194
195 while( !is_about_to_hop(ddx+dx*i,ddy+dy*i ) && i<16 ) {
196 i++;
197 }
198 set_xoff( ddx-(16-i)*dx );
199 set_yoff( ddy-(16-i)*dy );
200 if(file->is_loading()) {
201 if(dx && dy) {
202 steps = min( VEHICLE_STEPS_PER_TILE - 1, VEHICLE_STEPS_PER_TILE - 1 - (i*16) );
203 steps_next = VEHICLE_STEPS_PER_TILE - 1;
204 }
205 else {
206 steps = min( VEHICLE_STEPS_PER_TILE/2 - 1, VEHICLE_STEPS_PER_TILE / 2 -(i*16) );
207 steps_next = VEHICLE_STEPS_PER_TILE/2 ;
208 }
209 }
210 }
211
212 // the lifetime in ms
213 if(file->is_version_atleast(89, 5)) {
214 file->rdwr_long(time_to_life);
215 }
216 // there might be crashes if world is destroyed after loading
217 // without a sync-step being performed
218 if(file->is_loading() && time_to_life<=0) {
219 time_to_life = 1;
220 }
221
222 // Hajo: avoid endless growth of the values
223 // this causes lockups near 2**32
224 weg_next &= 65535;
225 }
226
finish_rd()227 void road_user_t::finish_rd()
228 {
229 calc_height(NULL);
230 calc_image();
231 }
232
233
234 /**********************************************************************************************************************/
235 /* statsauto_t (city cars) from here on */
236
237
238 static weighted_vector_tpl<const citycar_desc_t*> liste_timeline;
239 stringhashtable_tpl<const citycar_desc_t *> private_car_t::table;
240
register_desc(const citycar_desc_t * desc)241 bool private_car_t::register_desc(const citycar_desc_t *desc)
242 {
243 if( table.remove(desc->get_name()) ) {
244 dbg->doubled( "citycar", desc->get_name() );
245 }
246 table.put(desc->get_name(), desc);
247 return true;
248 }
249
250
251
successfully_loaded()252 bool private_car_t::successfully_loaded()
253 {
254 if(table.empty()) {
255 DBG_MESSAGE("private_car_t", "No citycars found - feature disabled");
256 }
257 return true;
258 }
259
260
compare_stadtauto_desc(const citycar_desc_t * a,const citycar_desc_t * b)261 static bool compare_stadtauto_desc(const citycar_desc_t* a, const citycar_desc_t* b)
262 {
263 int diff = a->get_intro_year_month() - b->get_intro_year_month();
264 if (diff == 0) {
265 diff = a->get_topspeed() - b->get_topspeed();
266 }
267 if (diff == 0) {
268 /* same Level - we introduce an artificial, but unique resort
269 * on the induced name. */
270 diff = strcmp(a->get_name(), b->get_name());
271 }
272 return diff < 0;
273 }
274
275
build_timeline_list(karte_t * welt)276 void private_car_t::build_timeline_list(karte_t *welt)
277 {
278 // this list will contain all citycars
279 liste_timeline.clear();
280 vector_tpl<const citycar_desc_t*> temp_liste(0);
281 if( !table.empty() ) {
282 const int month_now = welt->get_current_month();
283 //DBG_DEBUG("private_car_t::built_timeline_liste()","year=%i, month=%i", month_now/12, month_now%12+1);
284
285 // check for every citycar, if still ok ...
286 FOR(stringhashtable_tpl<citycar_desc_t const*>, const& i, table) {
287 citycar_desc_t const* const info = i.value;
288 const int intro_month = info->get_intro_year_month();
289 const int retire_month = info->get_retire_year_month();
290
291 if (!welt->use_timeline() || (intro_month <= month_now && month_now < retire_month)) {
292 temp_liste.insert_ordered( info, compare_stadtauto_desc );
293 }
294 }
295 }
296 liste_timeline.resize( temp_liste.get_count() );
297 FOR(vector_tpl<citycar_desc_t const*>, const i, temp_liste) {
298 liste_timeline.append(i, i->get_distribution_weight());
299 }
300 }
301
302
303
list_empty()304 bool private_car_t::list_empty()
305 {
306 return liste_timeline.empty();
307 }
308
309
310
~private_car_t()311 private_car_t::~private_car_t()
312 {
313 // first: release crossing
314 grund_t *gr = welt->lookup(get_pos());
315 if(gr && gr->ist_uebergang()) {
316 gr->find<crossing_t>(2)->release_crossing(this);
317 }
318
319 // just to be sure we are removed from this list!
320 if(time_to_life>0) {
321 welt->sync.remove(this);
322 }
323 welt->buche( -1, karte_t::WORLD_CITYCARS );
324 }
325
326
private_car_t(loadsave_t * file)327 private_car_t::private_car_t(loadsave_t *file) :
328 road_user_t()
329 {
330 rdwr(file);
331 ms_traffic_jam = 0;
332 calc_disp_lane();
333 if(desc) {
334 welt->sync.add(this);
335 }
336 welt->buche( +1, karte_t::WORLD_CITYCARS );
337 }
338
339
private_car_t(grund_t * gr,koord const target)340 private_car_t::private_car_t(grund_t* gr, koord const target) :
341 road_user_t(gr, simrand(65535)),
342 desc(liste_timeline.empty() ? 0 : pick_any_weighted(liste_timeline))
343 {
344 pos_next_next = koord3d::invalid;
345 time_to_life = welt->get_settings().get_stadtauto_duration() << 20; // ignore welt->ticks_per_world_month_shift;
346 current_speed = 48;
347 ms_traffic_jam = 0;
348 #ifdef DESTINATION_CITYCARS
349 this->target = target;
350 #else
351 (void)target;
352 #endif
353 calc_image();
354 calc_disp_lane();
355 welt->buche( +1, karte_t::WORLD_CITYCARS );
356 }
357
358
sync_step(uint32 delta_t)359 sync_result private_car_t::sync_step(uint32 delta_t)
360 {
361 time_to_life -= delta_t;
362 if( time_to_life<=0 ) {
363 return SYNC_DELETE;
364 }
365
366 if( current_speed==0 ) {
367 // stuck in traffic jam
368 uint32 old_ms_traffic_jam = ms_traffic_jam;
369 ms_traffic_jam += delta_t;
370 // check only every 1.024 s if stopped
371 if( (ms_traffic_jam>>10) != (old_ms_traffic_jam>>10) ) {
372 pos_next_next = koord3d::invalid;
373 if( hop_check() ) {
374 ms_traffic_jam = 0;
375 current_speed = 48;
376 }
377 else {
378 if( ms_traffic_jam > welt->ticks_per_world_month && old_ms_traffic_jam<=welt->ticks_per_world_month ) {
379 // message after two month, reset waiting timer
380 welt->get_message()->add_message( translator::translate("To heavy traffic\nresults in traffic jam.\n"), get_pos().get_2d(), message_t::traffic_jams, color_idx_to_rgb(COL_ORANGE) );
381 }
382 }
383 }
384 weg_next = 0;
385 }
386 else {
387 weg_next += current_speed*delta_t;
388 const uint32 distance = do_drive( weg_next );
389 // hop_check could have set weg_next to zero, check for possible underflow here
390 if (weg_next > distance) {
391 weg_next -= distance;
392 }
393 else {
394 weg_next = 0;
395 }
396 }
397
398 return time_to_life>0 ? SYNC_OK : SYNC_DELETE;
399 }
400
401
rdwr(loadsave_t * file)402 void private_car_t::rdwr(loadsave_t *file)
403 {
404 xml_tag_t s( file, "stadtauto_t" );
405
406 road_user_t::rdwr(file);
407
408 if(file->is_saving()) {
409 const char *s = desc->get_name();
410 file->rdwr_str(s);
411 }
412 else {
413 char s[256];
414 file->rdwr_str(s, lengthof(s));
415 desc = table.get(s);
416
417 if( desc == 0 && !liste_timeline.empty() ) {
418 dbg->warning("private_car_t::rdwr()", "Object '%s' not found in table, trying random stadtauto object type",s);
419 desc = pick_any_weighted(liste_timeline);
420 }
421
422 if(desc == 0) {
423 dbg->warning("private_car_t::rdwr()", "loading game with private cars, but no private car objects found in PAK files.");
424 }
425 else {
426 set_image(desc->get_image_id(ribi_t::get_dir(get_direction())));
427 }
428 }
429
430 if(file->is_version_less(86, 2)) {
431 time_to_life = simrand(1000000)+10000;
432 }
433 else if(file->is_version_less(89, 5)) {
434 file->rdwr_long(time_to_life);
435 time_to_life *= 10000; // converting from hops left to ms since start
436 }
437
438 if(file->is_version_less(86, 5)) {
439 // default starting speed for old games
440 if(file->is_loading()) {
441 current_speed = 48;
442 }
443 }
444 else {
445 sint32 dummy32=current_speed;
446 file->rdwr_long(dummy32);
447 current_speed = dummy32;
448 }
449
450 if(file->is_version_less(99, 10)) {
451 pos_next_next = koord3d::invalid;
452 }
453 else {
454 pos_next_next.rdwr(file);
455 }
456
457 // overtaking status
458 if(file->is_version_less(100, 1)) {
459 set_tiles_overtaking( 0 );
460 }
461 else {
462 file->rdwr_byte(tiles_overtaking);
463 set_tiles_overtaking( tiles_overtaking );
464 }
465 // do not start with zero speed!
466 current_speed ++;
467 }
468
469
ist_weg_frei(grund_t * gr)470 bool private_car_t::ist_weg_frei(grund_t *gr)
471 {
472 if(gr->get_top()>200) {
473 // already too many things here
474 return false;
475 }
476
477 // road still there?
478 weg_t * str = gr->get_weg(road_wt);
479 if(str==NULL) {
480 time_to_life = 0;
481 return false;
482 }
483
484 // calculate new direction
485 // are we just turning around?
486 const uint8 this_direction = get_direction();
487 bool frei = false;
488 if( get_pos()==pos_next_next ) {
489 // turning around => single check
490 const uint8 next_direction = ribi_t::backward(this_direction);
491 frei = (NULL == no_cars_blocking( gr, NULL, next_direction, next_direction, next_direction ));
492
493 // do not block railroad crossing
494 if(frei && str->is_crossing()) {
495 const grund_t *gr = welt->lookup(get_pos());
496 frei = (NULL == no_cars_blocking( gr, NULL, next_direction, next_direction, next_direction ));
497 }
498 }
499 else {
500 // driving on: check for crossings etc. too
501 const uint8 next_direction = this->calc_direction(get_pos(), pos_next_next);
502
503 // do not block this crossing (if possible)
504 if(ribi_t::is_threeway(str->get_ribi_unmasked())) {
505 // but leaving from railroad crossing is more important
506 grund_t *gr_here = welt->lookup(get_pos());
507 if( gr_here && gr_here->ist_uebergang() ) {
508 return true;
509 }
510 grund_t *test = welt->lookup(pos_next_next);
511 if( test ) {
512 uint8 next_90direction = this->calc_direction(pos_next, pos_next_next);
513 frei = (NULL == no_cars_blocking( gr, NULL, this_direction, next_direction, next_90direction ));
514 if( frei ) {
515 // check, if it can leave this crossings
516 frei = (NULL == no_cars_blocking( test, NULL, next_direction, next_90direction, next_90direction ));
517 }
518 }
519 // this fails with two crossings together; however, I see no easy way out here ...
520 }
521 else {
522 // not a crossing => skip 90� check!
523 frei = true;
524 // Overtaking vehicles shouldn't have anything blocking them
525 if( !is_overtaking() ) {
526 // not a crossing => skip 90� check!
527 vehicle_base_t *dt = no_cars_blocking( gr, NULL, this_direction, next_direction, next_direction );
528 if( dt ) {
529 if(dt->is_stuck()) {
530 // previous vehicle is stuck => end of traffic jam ...
531 frei = false;
532 }
533 else {
534 overtaker_t *over = dt->get_overtaker();
535 if(over) {
536 if(!over->is_overtaking()) {
537 // otherwise the overtaken car would stop for us ...
538 if( road_vehicle_t const* const car = obj_cast<road_vehicle_t>(dt) ) {
539 convoi_t* const ocnv = car->get_convoi();
540 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()) ) {
541 frei = false;
542 }
543 } else if( private_car_t* const caut = obj_cast<private_car_t>(dt) ) {
544 if( !can_overtake(caut, caut->get_desc()->get_topspeed(), VEHICLE_STEPS_PER_TILE) ) {
545 frei = false;
546 }
547 }
548 }
549 }
550 else {
551 // movingobj ... block road totally
552 frei = false;
553 }
554 }
555 }
556 }
557 }
558
559 // do not block railroad crossing
560 if( frei && str->is_crossing() ) {
561 // can we cross?
562 crossing_t* cr = gr->find<crossing_t>(2);
563 if( cr && !cr->request_crossing(this)) {
564 // approaching railway crossing: check if empty
565 return false;
566 }
567 // no further check, when already entered a crossing (to allow leaving it)
568 grund_t *gr_here = welt->lookup(get_pos());
569 if(gr_here && gr_here->ist_uebergang()) {
570 return true;
571 }
572 // ok, now check for free exit
573 koord dir = pos_next.get_2d()-get_pos().get_2d();
574 koord3d checkpos = pos_next+dir;
575 uint8 number_reversed = 0;
576 while( number_reversed<2 ) {
577 const grund_t *test = welt->lookup(checkpos);
578 if(!test) {
579 // should not reach here ! (z9999)
580 break;
581 }
582 const uint8 next_direction = ribi_type(dir);
583 const uint8 nextnext_direction = ribi_type(dir);
584 // test next field after way crossing
585 if(no_cars_blocking( test, NULL, next_direction, nextnext_direction, nextnext_direction )) {
586 return false;
587 }
588 // ok, left the crossing
589 if(!test->find<crossing_t>(2)) {
590 // approaching railway crossing: check if empty
591 crossing_t* cr = gr->find<crossing_t>(2);
592 return cr->request_crossing( this );
593 }
594 else {
595 // seems to be a dead-end.
596 if( (test->get_weg_ribi(road_wt)&next_direction) == 0 ) {
597 // will be going back
598 pos_next_next=get_pos();
599 // check also opposite direction are free
600 dir = -dir;
601 number_reversed ++;
602 }
603 }
604 checkpos += dir;
605 }
606 }
607 }
608
609 if(frei && current_speed==0) {
610 ms_traffic_jam = 0;
611 current_speed = 48;
612 }
613
614 if(!frei) {
615 // not free => stop overtaking
616 this->set_tiles_overtaking(0);
617 }
618
619 return frei;
620 }
621
622
enter_tile(grund_t * gr)623 void private_car_t::enter_tile(grund_t* gr)
624 {
625 #ifdef DESTINATION_CITYCARS
626 if( target!=koord::invalid && koord_distance(pos_next.get_2d(),target)<10 ) {
627 // delete it ...
628 time_to_life = 0;
629 // was generating pedestrians gere, but not possible with new sync system
630 }
631 #endif
632 vehicle_base_t::enter_tile(gr);
633 calc_disp_lane();
634 gr->get_weg(road_wt)->book(1, WAY_STAT_CONVOIS);
635 }
636
637
hop_check()638 grund_t* private_car_t::hop_check()
639 {
640 // V.Meyer: weg_position_t changed to grund_t::get_neighbour()
641 grund_t *const from = welt->lookup(pos_next);
642 if(from==NULL) {
643 // nothing to go? => destroy ...
644 time_to_life = 0;
645 return NULL;
646 }
647
648 // find the allowed directions
649 const weg_t *weg = from->get_weg(road_wt);
650 if(weg==NULL) {
651 // nothing to go? => destroy ...
652 time_to_life = 0;
653 return NULL;
654 }
655
656 // traffic light phase check (since this is on next tile, it will always be necessary!)
657 const ribi_t::ribi direction90 = ribi_type(get_pos(), pos_next);
658
659 if( weg->has_sign( )) {
660 const roadsign_t* rs = from->find<roadsign_t>();
661 const roadsign_desc_t* rs_desc = rs->get_desc();
662 if(rs_desc->is_traffic_light() && (rs->get_dir()&direction90)==0) {
663 direction = direction90;
664 calc_image();
665 // wait here
666 current_speed = 48;
667 weg_next = 0;
668 return NULL;
669 }
670 }
671
672 // next tile unknown => find next tile
673 if(pos_next_next==koord3d::invalid) {
674
675 // ok, nobody did delete the road in front of us
676 // so we can check for valid directions
677 ribi_t::ribi ribi = weg->get_ribi() & (~ribi_t::backward(direction90));
678
679 // cul de sac: return
680 if(ribi==0) {
681 pos_next_next = get_pos();
682 return ist_weg_frei(from) ? from : NULL;
683 }
684
685 #ifdef DESTINATION_CITYCARS
686 static weighted_vector_tpl<koord3d> posliste(4);
687 posliste.clear();
688 const uint8 offset = ribi_t::is_single(ribi) ? 0 : simrand(4);
689 for(uint8 r = 0; r < 4; r++) {
690 if( get_pos().get_2d()==koord::nsew[r]+pos_next.get_2d() ) {
691 continue;
692 }
693 #else
694 const uint8 offset = ribi_t::is_single(ribi) ? 0 : simrand(4);
695 for(uint8 i = 0; i < 4; i++) {
696 const uint8 r = (i+offset)&3;
697 #endif
698 if( (ribi&ribi_t::nsew[r])!=0 ) {
699 grund_t *to;
700 if( from->get_neighbour(to, road_wt, ribi_t::nsew[r]) ) {
701 // check, if this is just a single tile deep after a crossing
702 weg_t *w = to->get_weg(road_wt);
703 if( ribi_t::is_single(w->get_ribi()) && (w->get_ribi()&ribi_t::nsew[r])==0 && !ribi_t::is_single(ribi) ) {
704 ribi &= ~ribi_t::nsew[r];
705 continue;
706 }
707 // check, if roadsign forbid next step ...
708 if(w->has_sign()) {
709 const roadsign_t* rs = to->find<roadsign_t>();
710 const roadsign_desc_t* rs_desc = rs->get_desc();
711 if(rs_desc->get_min_speed()>desc->get_topspeed() || (rs_desc->is_private_way() && (rs->get_player_mask()&2)==0) ) {
712 // not allowed to go here
713 ribi &= ~ribi_t::nsew[r];
714 continue;
715 }
716 }
717 #ifdef DESTINATION_CITYCARS
718 uint32 dist=koord_distance( to->get_pos().get_2d(), target );
719 posliste.append( to->get_pos(), dist*dist );
720 #else
721 // ok, now check if we are allowed to go here (i.e. no cars blocking)
722 pos_next_next = to->get_pos();
723 if(ist_weg_frei(from)) {
724 // ok, this direction is fine!
725 ms_traffic_jam = 0;
726 if(current_speed<48) {
727 current_speed = 48;
728 }
729 return from;
730 }
731 else {
732 pos_next_next = koord3d::invalid;
733 }
734 #endif
735 }
736 else {
737 // not connected?!? => ribi likely wrong
738 ribi &= ~ribi_t::nsew[r];
739 }
740 }
741 }
742 #ifdef DESTINATION_CITYCARS
743 if (!posliste.empty()) {
744 pos_next_next = pick_any_weighted(posliste);
745 }
746 else {
747 pos_next_next = get_pos();
748 }
749 if(ist_weg_frei(from)) {
750 // ok, this direction is fine!
751 ms_traffic_jam = 0;
752 if(current_speed<48) {
753 current_speed = 48;
754 }
755 return from;
756 }
757 #else
758 // only stumps at single way crossing, all other blocked => turn around
759 if(ribi==0) {
760 pos_next_next = get_pos();
761 return ist_weg_frei(from) ? from : NULL;
762 }
763 #endif
764 }
765 else {
766 if(from && ist_weg_frei(from)) {
767 // ok, this direction is fine!
768 ms_traffic_jam = 0;
769 if(current_speed<48) {
770 current_speed = 48;
771 }
772 return from;
773 }
774 }
775 // no free tiles => assume traffic jam ...
776 pos_next_next = koord3d::invalid;
777 current_speed = 0;
778 set_tiles_overtaking( 0 );
779 return NULL;
780 }
781
782
783
784 void private_car_t::hop(grund_t* to)
785 {
786 leave_tile();
787
788 if(pos_next_next==get_pos()) {
789 direction = calc_set_direction( pos_next, pos_next_next );
790 steps_next = 0; // mark for starting at end of tile!
791 }
792 else {
793 direction = calc_set_direction( get_pos(), pos_next_next );
794 }
795 calc_image();
796
797 // and add to next tile
798 set_pos(pos_next);
799 enter_tile(to);
800
801 calc_current_speed(to);
802
803 update_tiles_overtaking();
804 if(to->ist_uebergang()) {
805 to->find<crossing_t>(2)->add_to_crossing(this);
806 }
807 pos_next = pos_next_next;
808 pos_next_next = koord3d::invalid;
809 }
810
811
812 void private_car_t::calc_image()
813 {
814 set_image(desc->get_image_id(ribi_t::get_dir(get_direction())));
815 }
816
817
818 void private_car_t::calc_current_speed(grund_t* gr)
819 {
820 const weg_t * weg = gr->get_weg(road_wt);
821 const sint32 max_speed = desc->get_topspeed();
822 const sint32 speed_limit = weg ? kmh_to_speed(weg->get_max_speed()) : max_speed;
823 current_speed += max_speed>>2;
824 if(current_speed > max_speed) {
825 current_speed = max_speed;
826 }
827 if(current_speed > speed_limit) {
828 current_speed = speed_limit;
829 }
830 }
831
832
833 void private_car_t::info(cbuffer_t & buf) const
834 {
835 buf.printf(translator::translate("%s\nspeed %i\nmax_speed %i\ndx:%i dy:%i"), translator::translate(desc->get_name()), speed_to_kmh(current_speed), speed_to_kmh(desc->get_topspeed()), dx, dy);
836
837 if (char const* const maker = desc->get_copyright()) {
838 buf.printf(translator::translate("Constructed by %s"), maker);
839 }
840 }
841
842
843 // to make smaller steps than the tile granularity, we have to use this trick
844 void private_car_t::get_screen_offset( int &xoff, int &yoff, const sint16 raster_width ) const
845 {
846 vehicle_base_t::get_screen_offset( xoff, yoff, raster_width );
847
848 if( welt->get_settings().is_drive_left() ) {
849 const int drive_left_dir = ribi_t::get_dir(get_direction());
850 xoff += tile_raster_scale_x( driveleft_base_offsets[drive_left_dir][0], raster_width );
851 yoff += tile_raster_scale_y( driveleft_base_offsets[drive_left_dir][1], raster_width );
852 }
853
854 // eventually shift position to take care of overtaking
855 if( is_overtaking() ) {
856 xoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width);
857 yoff += tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width);
858 }
859 else if( is_overtaken() ) {
860 xoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][0], raster_width)/5;
861 yoff -= tile_raster_scale_x(overtaking_base_offsets[ribi_t::get_dir(get_direction())][1], raster_width)/5;
862 }
863 }
864
865
866 void private_car_t::calc_disp_lane()
867 {
868 // driving in the back or the front
869 ribi_t::ribi test_dir = welt->get_settings().is_drive_left() ? ribi_t::northeast : ribi_t::southwest;
870 disp_lane = get_direction() & test_dir ? 1 : 3;
871 }
872
873 void private_car_t::rotate90()
874 {
875 road_user_t::rotate90();
876 calc_disp_lane();
877 }
878
879 /**
880 * conditions for a city car to overtake another overtaker.
881 * The city car is not overtaking/being overtaken.
882 * @author isidoro
883 */
884 bool private_car_t::can_overtake( overtaker_t *other_overtaker, sint32 other_speed, sint16 steps_other)
885 {
886 if( !other_overtaker->can_be_overtaken() ) {
887 return false;
888 }
889
890 if( other_speed == 0 ) {
891 /* overtaking a loading convoi
892 * => we can do a lazy check, since halts are always straight
893 */
894 grund_t *gr = welt->lookup(get_pos());
895 if( gr==NULL ) {
896 // should never happen, since there is a vehicle in front of us ...
897 return false;
898 }
899 weg_t *str = gr->get_weg(road_wt);
900 if( str==0 ) {
901 // also this is not possible, since a car loads in front of is!?!
902 return false;
903 }
904
905 const ribi_t::ribi direction = get_direction() & str->get_ribi();
906 koord3d check_pos = get_pos()+koord((ribi_t::ribi)(str->get_ribi()&direction));
907 for( int tiles=1+(steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT); tiles>=0; tiles-- ) {
908 grund_t *gr = welt->lookup(check_pos);
909 if( gr==NULL ) {
910 return false;
911 }
912 weg_t *str = gr->get_weg(road_wt);
913 if( str==0 ) {
914 return false;
915 }
916 // not overtaking on railroad crossings ...
917 if( str->is_crossing() ) {
918 return false;
919 }
920 if( ribi_t::is_threeway(str->get_ribi()) ) {
921 return false;
922 }
923 // Check for other vehicles on the next tile
924 const uint8 top = gr->get_top();
925 for( uint8 j=1; j<top; j++ ) {
926 if( vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(j)) ) {
927 // check for other traffic on the road
928 const overtaker_t *ov = v->get_overtaker();
929 if(ov) {
930 if(this!=ov && other_overtaker!=ov) {
931 return false;
932 }
933 }
934 else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) {
935 return false;
936 }
937 }
938 }
939 check_pos += koord(direction);
940 }
941 set_tiles_overtaking( 3+(steps_other-1)/(CARUNITS_PER_TILE*VEHICLE_STEPS_PER_CARUNIT) );
942 return true;
943 }
944
945 sint32 diff_speed = (sint32)current_speed - other_speed;
946 if( diff_speed < kmh_to_speed(5) ) {
947 // not fast enough to overtake
948 return false;
949 }
950
951 // Number of tiles overtaking will take
952 int n_tiles = 0;
953
954 /* Distance it takes overtaking (unit: vehicle steps) = my_speed * time_overtaking
955 * time_overtaking = tiles_to_overtake/diff_speed
956 * tiles_to_overtake = convoi_length + pos_other_convoi
957 * convoi_length for city cars? ==> a bit over half a tile (10)
958 */
959 sint32 time_overtaking = 0;
960 sint32 distance = current_speed*((10<<4)+steps_other)/max(desc->get_topspeed()-other_speed,diff_speed);
961
962 // Conditions for overtaking:
963 // Flat tiles, with no stops, no crossings, no signs, no change of road speed limit
964 koord3d check_pos = get_pos();
965 koord pos_prev = check_pos.get_2d();
966
967 grund_t *gr = welt->lookup(check_pos);
968 if( gr==NULL ) {
969 return false;
970 }
971
972 weg_t *str = gr->get_weg(road_wt);
973 if( str==0 ) {
974 return false;
975 }
976
977 // we need 90 degree ribi
978 ribi_t::ribi direction = get_direction();
979 direction = str->get_ribi() & direction;
980
981 while( distance > 0 ) {
982
983 // we allow stops and slopes, since empty stops and slopes cannot affect us
984 // (citycars do not slow down on slopes!)
985
986 // start of bridge is one level deeper
987 if(gr->get_weg_yoff()>0) {
988 check_pos.z ++;
989 }
990
991 // special signs
992 if( str->has_sign() && str->get_ribi()==str->get_ribi_unmasked() ) {
993 const roadsign_t *rs = gr->find<roadsign_t>(1);
994 if(rs) {
995 const roadsign_desc_t *rb = rs->get_desc();
996 if(rb->get_min_speed()>desc->get_topspeed() || rb->is_private_way() || rb->is_traffic_light() ) {
997 // do not overtake when road is closed for cars, there is a traffic light or a too high min speed limit
998 return false;
999 }
1000 }
1001 }
1002
1003 // not overtaking on railroad crossings ...
1004 if( str->is_crossing() ) {
1005 return false;
1006 }
1007
1008 // street gets too slow (TODO: should be able to be correctly accounted for)
1009 if( desc->get_topspeed() > kmh_to_speed(str->get_max_speed()) ) {
1010 return false;
1011 }
1012
1013 int d = ribi_t::is_straight(str->get_ribi()) ? VEHICLE_STEPS_PER_TILE : diagonal_vehicle_steps_per_tile;
1014 distance -= d;
1015 time_overtaking += d;
1016
1017 n_tiles++;
1018
1019 /* Now we must check for next position:
1020 * crossings are ok, as long as we cannot exit there due to one way signs
1021 * much cheaper calculation: only go on in the direction of before (since no slopes allowed anyway ... )
1022 */
1023 grund_t *to = welt->lookup( check_pos + koord((ribi_t::ribi)(str->get_ribi()&direction)) );
1024 if( ribi_t::is_threeway(str->get_ribi()) || to==NULL) {
1025 // check for entries/exits/bridges, if necessary
1026 ribi_t::ribi rib = str->get_ribi();
1027 bool found_one = false;
1028 for( int r=0; r<4; r++ ) {
1029 if( (rib&ribi_t::nsew[r])==0 || check_pos.get_2d()+koord::nsew[r]==pos_prev) {
1030 continue;
1031 }
1032 if(gr->get_neighbour(to, road_wt, ribi_t::nsew[r])) {
1033 if(found_one) {
1034 // two directions to go: unexpected cars may occurs => abort
1035 return false;
1036 }
1037 found_one = true;
1038 }
1039 }
1040 }
1041 pos_prev = check_pos.get_2d();
1042
1043 // nowhere to go => nobody can come against us ...
1044 if(to==NULL || (str=to->get_weg(road_wt))==NULL) {
1045 return false;
1046 }
1047
1048 // Check for other vehicles on the next tile
1049 const uint8 top = gr->get_top();
1050 for( uint8 j=1; j<top; j++ ) {
1051 if( vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(j)) ) {
1052 // check for other traffic on the road
1053 const overtaker_t *ov = v->get_overtaker();
1054 if(ov) {
1055 if(this!=ov && other_overtaker!=ov) {
1056 return false;
1057 }
1058 }
1059 else if( v->get_waytype()==road_wt && v->get_typ()!=obj_t::pedestrian ) {
1060 return false;
1061 }
1062 }
1063 }
1064
1065 gr = to;
1066 check_pos = to->get_pos();
1067
1068 direction = ~ribi_type( check_pos, pos_prev ) & str->get_ribi();
1069 }
1070
1071 // Second phase: only facing traffic is forbidden
1072 // Since street speed can change, we do the calculation with time.
1073 // Each empty tile will subtract tile_dimension/max_street_speed.
1074 // If time is exhausted, we are guaranteed that no facing traffic will
1075 // invade the dangerous zone.
1076 time_overtaking = (time_overtaking << 16)/(sint32)current_speed;
1077 do {
1078 // we can allow crossings or traffic lights here, since they will stop also oncoming traffic
1079 if( ribi_t::is_straight(str->get_ribi()) ) {
1080 time_overtaking -= (VEHICLE_STEPS_PER_TILE<<16) / kmh_to_speed(str->get_max_speed());
1081 }
1082 else {
1083 time_overtaking -= (diagonal_vehicle_steps_per_tile<<16) / kmh_to_speed(str->get_max_speed());
1084 }
1085
1086 // start of bridge is one level deeper
1087 if(gr->get_weg_yoff()>0) {
1088 check_pos.z ++;
1089 }
1090
1091 // much cheaper calculation: only go on in the direction of before ...
1092 grund_t *to = welt->lookup( check_pos + koord((ribi_t::ribi)(str->get_ribi()&direction)) );
1093 if( ribi_t::is_threeway(str->get_ribi()) || to==NULL ) {
1094 // check for crossings/bridges, if necessary
1095 bool found_one = false;
1096 for( int r=0; r<4; r++ ) {
1097 if(check_pos.get_2d()+koord::nsew[r]==pos_prev) {
1098 continue;
1099 }
1100 if(gr->get_neighbour(to, road_wt, ribi_t::nsew[r])) {
1101 if(found_one) {
1102 return false;
1103 }
1104 found_one = true;
1105 }
1106 }
1107 }
1108
1109 koord pos_prev_prev = pos_prev;
1110 pos_prev = check_pos.get_2d();
1111
1112 // nowhere to go => nobody can come against us ...
1113 if(to==NULL || (str=to->get_weg(road_wt))==NULL) {
1114 break;
1115 }
1116
1117 // Check for other vehicles in facing direction
1118 // now only I know direction on this tile ...
1119 ribi_t::ribi their_direction = ribi_t::backward(calc_direction( pos_prev_prev, to->get_pos()));
1120 const uint8 top = gr->get_top();
1121 for( uint8 j=1; j<top; j++ ) {
1122 vehicle_base_t* const v = obj_cast<vehicle_base_t>(gr->obj_bei(j));
1123 if( v && v->get_direction() == their_direction ) {
1124 // check for car
1125 if(v->get_overtaker()) {
1126 return false;
1127 }
1128 }
1129 }
1130
1131 gr = to;
1132 check_pos = to->get_pos();
1133
1134 direction = ~ribi_type( check_pos, pos_prev ) & str->get_ribi();
1135 } while( time_overtaking > 0 );
1136
1137 set_tiles_overtaking( 1+n_tiles );
1138 other_overtaker->set_tiles_overtaking( -1-(n_tiles/2) );
1139
1140 return true;
1141 }
1142