~ubuntu-branches/ubuntu/raring/simutrans/raring-proposed

« back to all changes in this revision

Viewing changes to simhalt.cc

  • Committer: Package Import Robot
  • Author(s): Ansgar Burchardt
  • Date: 2011-11-03 19:59:02 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20111103195902-uopgwf488mfctb75
Tags: 111.0-1
* New upstream release.
* debian/rules: Update get-orig-source target for new upstream release.
* Use xz compression for source and binary packages.
* Use override_* targets to simplify debian/rules.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
 
2
 * Copyright (c) 1997 - 2001 Hansj. Malthaner
3
3
 *
4
4
 * This file is part of the Simutrans project under the artistic licence.
5
5
 * (see licence.txt)
62
62
 
63
63
#include "vehicle/simpeople.h"
64
64
 
65
 
 
66
65
karte_t *haltestelle_t::welt = NULL;
67
66
 
68
67
slist_tpl<halthandle_t> haltestelle_t::alle_haltestellen;
69
68
 
70
69
stringhashtable_tpl<halthandle_t> haltestelle_t::all_names;
71
70
 
72
 
static uint32 halt_iterator_start = 0;
73
71
uint8 haltestelle_t::status_step = 0;
74
 
 
75
 
/**
76
 
 * Markers used in suche_route() to avoid processing the same halt more than once
77
 
 * Originally they are instance variables of haltestelle_t
78
 
 * Now consolidated into a static array to speed up suche_route()
79
 
 * @author Knightly
80
 
 */
81
 
uint8 haltestelle_t::markers[65536];
82
 
uint8 haltestelle_t::current_mark = 0;
83
 
 
 
72
uint8 haltestelle_t::reconnect_counter = 0;
84
73
 
85
74
void haltestelle_t::step_all()
86
75
{
87
 
        if(  alle_haltestellen.get_count()>0  ) {
 
76
        static slist_tpl<halthandle_t>::iterator iter( alle_haltestellen.begin() );
 
77
        if (alle_haltestellen.empty()) {
 
78
                return;
 
79
        }
 
80
        const uint8 schedule_counter = welt->get_schedule_counter();
 
81
        if (reconnect_counter != schedule_counter) {
 
82
                // always start with reconnection, rerouting will happen after complete reconnection
 
83
                status_step = RECONNECTING;
 
84
                reconnect_counter = schedule_counter;
 
85
                iter = alle_haltestellen.begin();
 
86
        }
88
87
 
89
 
                uint32 it = halt_iterator_start;
90
 
                slist_iterator_tpl <halthandle_t> iter( alle_haltestellen );
91
 
                while(  it>0  &&  iter.next()  ) {
92
 
                        it--;
93
 
                }
94
 
                if(  it>0  ) {
95
 
                        halt_iterator_start = 0;
96
 
                }
97
 
                else {
98
 
                        sint16 units_remaining = 128;
99
 
                        while(  units_remaining>0  ) {
100
 
                                if(  !iter.next()  ) {
101
 
                                        halt_iterator_start = 0;
102
 
                                        break;
103
 
                                }
104
 
                                // iterate until the specified number of units were handled
105
 
                                if(  !iter.get_current()->step(units_remaining)  ) {
106
 
                                        // too much rerouted => needs continue at next round!
107
 
                                        break;
108
 
                                }
109
 
                                halt_iterator_start ++;
110
 
                        }
 
88
        sint16 units_remaining = 128;
 
89
        for(; !iter.end()  &&   units_remaining>0; ++iter) {
 
90
                // iterate until the specified number of units were handled
 
91
                if(  !(*iter)->step(status_step, units_remaining)  ) {
 
92
                        // too much rerouted => needs to continue at next round!
 
93
                        break;
111
94
                }
112
95
        }
113
 
        else {
114
 
                // save reinit
115
 
                halt_iterator_start = 0;
 
96
        // ready?
 
97
        if (iter.end()) {
 
98
                if (status_step == RECONNECTING) {
 
99
                        // reroute in next call
 
100
                        status_step = REROUTING;
 
101
                }
 
102
                else if (status_step == REROUTING) {
 
103
                        status_step = 0;
 
104
                }
 
105
                iter = alle_haltestellen.begin();
116
106
        }
117
107
}
118
108
 
119
109
 
120
110
 
121
 
halthandle_t haltestelle_t::get_halt( karte_t *welt, const koord pos, const spieler_t *sp )
 
111
halthandle_t haltestelle_t::get_halt(const karte_t *welt, const koord pos, const spieler_t *sp )
122
112
{
123
113
        const planquadrat_t *plan = welt->lookup(pos);
124
114
        if(plan) {
148
138
}
149
139
 
150
140
 
151
 
halthandle_t haltestelle_t::get_halt( karte_t *welt, const koord3d pos, const spieler_t *sp )
 
141
halthandle_t haltestelle_t::get_halt(const karte_t *welt, const koord3d pos, const spieler_t *sp )
152
142
{
153
143
        const grund_t *gr = welt->lookup(pos);
154
144
        if(gr) {
281
271
 */
282
272
void haltestelle_t::destroy(halthandle_t &halt)
283
273
{
284
 
        // jsut play save: restart iterator at zero ...
285
 
        halt_iterator_start = 0;
286
274
        delete halt.get_rep();
287
275
}
288
276
 
300
288
                halthandle_t halt = alle_haltestellen.front();
301
289
                destroy(halt);
302
290
        }
 
291
        status_step = 0;
303
292
}
304
293
 
305
294
 
306
295
haltestelle_t::haltestelle_t(karte_t* wl, loadsave_t* file)
307
296
{
308
 
        self = halthandle_t(this);
309
 
        markers[ self.get_id() ] = current_mark;
310
297
        last_loading_step = wl->get_steps();
311
298
 
312
299
        welt = wl;
316
303
        pax_no_route = 0;
317
304
 
318
305
        waren = (vector_tpl<ware_t> **)calloc( warenbauer_t::get_max_catg_index(), sizeof(vector_tpl<ware_t> *) );
319
 
        warenziele = new vector_tpl<halthandle_t>[ warenbauer_t::get_max_catg_index() ];
320
 
        non_identical_schedules = new uint8[ warenbauer_t::get_max_catg_index() ];
 
306
        connections = new vector_tpl<connection_t>[ warenbauer_t::get_max_catg_index() ];
 
307
        serving_schedules = new uint8[ warenbauer_t::get_max_catg_index() ];
321
308
 
322
309
        for ( uint8 i = 0; i < warenbauer_t::get_max_catg_index(); i++ ) {
323
 
                non_identical_schedules[i] = 0;
 
310
                serving_schedules[i] = 0;
324
311
        }
325
312
 
326
313
        status_color = COL_YELLOW;
327
314
 
328
 
        reroute_counter = welt->get_schedule_counter()-1;
329
 
        rebuilt_destination_counter = reroute_counter;
 
315
        reconnect_counter = welt->get_schedule_counter()-1;
330
316
 
331
317
        enables = NOT_ENABLED;
332
318
 
336
322
 
337
323
        rdwr(file);
338
324
 
 
325
        markers[ self.get_id() ] = current_marker;
 
326
 
339
327
        alle_haltestellen.append(self);
340
328
}
341
329
 
346
334
        assert( !alle_haltestellen.is_contained(self) );
347
335
        alle_haltestellen.append(self);
348
336
 
349
 
        markers[ self.get_id() ] = current_mark;
 
337
        markers[ self.get_id() ] = current_marker;
350
338
 
351
339
        last_loading_step = wl->get_steps();
352
340
        welt = wl;
355
343
        besitzer_p = sp;
356
344
 
357
345
        enables = NOT_ENABLED;
358
 
 
359
 
        reroute_counter = welt->get_schedule_counter()-1;
360
 
        rebuilt_destination_counter = reroute_counter;
361
 
        last_catg_index = 255;  // force total reouting
 
346
        // force total reouting
 
347
        reconnect_counter = welt->get_schedule_counter()-1;
 
348
        last_catg_index = 255;
362
349
 
363
350
        waren = (vector_tpl<ware_t> **)calloc( warenbauer_t::get_max_catg_index(), sizeof(vector_tpl<ware_t> *) );
364
 
        warenziele = new vector_tpl<halthandle_t>[ warenbauer_t::get_max_catg_index() ];
365
 
        non_identical_schedules = new uint8[ warenbauer_t::get_max_catg_index() ];
 
351
        connections = new vector_tpl<connection_t>[ warenbauer_t::get_max_catg_index() ];
 
352
        serving_schedules = new uint8[ warenbauer_t::get_max_catg_index() ];
366
353
 
367
354
        for ( uint8 i = 0; i < warenbauer_t::get_max_catg_index(); i++ ) {
368
 
                non_identical_schedules[i] = 0;
 
355
                serving_schedules[i] = 0;
369
356
        }
370
357
 
371
358
        pax_happy = 0;
430
417
        }
431
418
 
432
419
        // remove from all haltlists
433
 
        ul.x = max( 0, ul.x-welt->get_einstellungen()->get_station_coverage() );
434
 
        ul.y = max( 0, ul.y-welt->get_einstellungen()->get_station_coverage() );
435
 
        lr.x = min( welt->get_groesse_x(), lr.x+1+welt->get_einstellungen()->get_station_coverage() );
436
 
        lr.y = min( welt->get_groesse_y(), lr.y+1+welt->get_einstellungen()->get_station_coverage() );
 
420
        uint16 const cov = welt->get_settings().get_station_coverage();
 
421
        ul.x = max(0, ul.x - cov);
 
422
        ul.y = max(0, ul.y - cov);
 
423
        lr.x = min(welt->get_groesse_x(), lr.x + 1 + cov);
 
424
        lr.y = min(welt->get_groesse_y(), lr.y + 1 + cov);
437
425
        for(  int y=ul.y;  y<lr.y;  y++  ) {
438
426
                for(  int x=ul.x;  x<lr.x;  x++  ) {
439
427
                        planquadrat_t *plan = welt->access(x,y);
457
445
                }
458
446
        }
459
447
        free( waren );
460
 
        delete[] warenziele;
461
 
        delete[] non_identical_schedules;
 
448
        delete[] connections;
 
449
        delete[] serving_schedules;
462
450
 
463
451
        // routes may have changed without this station ...
464
452
        verbinde_fabriken();
546
534
}
547
535
 
548
536
 
 
537
// returns the number of % in a printf string ....
 
538
static int count_printf_param( const char *str )
 
539
{
 
540
        int count = 0;
 
541
        while( *str!=0  ) {
 
542
                if(  *str=='%'  ) {
 
543
                        str++;
 
544
                        if(  *str!='%'  ) {
 
545
                                count++;
 
546
                        }
 
547
                }
 
548
                str ++;
 
549
        }
 
550
        return count;
 
551
}
 
552
 
549
553
 
550
554
// creates stops with unique! names
551
 
char *haltestelle_t::create_name(const koord k, const char *typ, const int lang)
 
555
char* haltestelle_t::create_name(koord const k, char const* const typ)
552
556
{
 
557
        int const lang = welt->get_settings().get_name_language_id();
553
558
        stadt_t *stadt = welt->suche_naechste_stadt(k);
554
559
        const char *stop = translator::translate(typ,lang);
555
 
        char buf[1024];
 
560
        cbuffer_t buf;
556
561
 
557
562
        // this fails only, if there are no towns at all!
558
563
        if(stadt==NULL) {
559
564
                // get a default name
560
 
                sprintf( buf, translator::translate("land stop %i %s",lang), get_besitzer()->get_haltcount(), stop );
 
565
                buf.printf( translator::translate("land stop %i %s",lang), get_besitzer()->get_haltcount(), stop );
561
566
                return strdup(buf);
562
567
        }
563
568
 
570
575
 
571
576
        // strings for intown / outside of town
572
577
        const bool inside = (li_gr < k.x  &&  re_gr > k.x  &&  ob_gr < k.y  &&  un_gr > k.y);
573
 
 
574
 
        if(!welt->get_einstellungen()->get_numbered_stations()) {
575
 
 
 
578
        const bool suburb = !inside  &&  (li_gr - 6 < k.x  &&  re_gr + 6 > k.x  &&  ob_gr - 6 < k.y  &&  un_gr + 6 > k.y);
 
579
 
 
580
        if (!welt->get_settings().get_numbered_stations()) {
576
581
                static const koord next_building[24] = {
577
582
                        koord( 0, -1), // nord
578
583
                        koord( 1,  0), // ost
603
608
                // standard names:
604
609
                // order: factory, attraction, direction, normal name
605
610
                // prissi: first we try a factory name
606
 
                slist_tpl<fabrik_t *>fabs;
607
 
                if (self.is_bound()) {
608
 
                        // first factories (so with same distance, they have priority)
609
 
                        int this_distance = 999;
610
 
                        slist_iterator_tpl<fabrik_t*> fab_iter(get_fab_list());
 
611
 
 
612
                // is there a translation for factory defined?
 
613
                const char *fab_base_text = "%s factory %s %s";
 
614
                const char *fab_base = translator::translate(fab_base_text,lang);
 
615
                if(  fab_base_text != fab_base  ) {
 
616
                        slist_tpl<fabrik_t *>fabs;
 
617
                        if (self.is_bound()) {
 
618
                                // first factories (so with same distance, they have priority)
 
619
                                int this_distance = 999;
 
620
                                slist_iterator_tpl<fabrik_t*> fab_iter(get_fab_list());
 
621
                                while (fab_iter.next()) {
 
622
                                        int distance = koord_distance(fab_iter.get_current()->get_pos().get_2d(), k);
 
623
                                        if (distance < this_distance) {
 
624
                                                fabs.insert(fab_iter.get_current());
 
625
                                                distance = this_distance;
 
626
                                        }
 
627
                                        else {
 
628
                                                fabs.append(fab_iter.get_current());
 
629
                                        }
 
630
                                }
 
631
                        }
 
632
                        else {
 
633
                                // since the distance are presorted, we can just append for a good choice ...
 
634
                                for(  int test=0;  test<24;  test++  ) {
 
635
                                        fabrik_t *fab = fabrik_t::get_fab(welt,k+next_building[test]);
 
636
                                        if(fab  &&  fabs.is_contained(fab)) {
 
637
                                                fabs.append(fab);
 
638
                                        }
 
639
                                }
 
640
                        }
 
641
 
 
642
                        // are there fabs?
 
643
                        slist_iterator_tpl<fabrik_t*> fab_iter(fabs);
611
644
                        while (fab_iter.next()) {
612
 
                                int distance = koord_distance(fab_iter.get_current()->get_pos().get_2d(), k);
613
 
                                if (distance < this_distance) {
614
 
                                        fabs.insert(fab_iter.get_current());
615
 
                                        distance = this_distance;
616
 
                                }
617
 
                                else {
618
 
                                        fabs.append(fab_iter.get_current());
619
 
                                }
620
 
                        }
621
 
                }
622
 
                else {
623
 
                        // since the distance are presorted, we can just append for a good choice ...
624
 
                        for(  int test=0;  test<24;  test++  ) {
625
 
                                fabrik_t *fab = fabrik_t::get_fab(welt,k+next_building[test]);
626
 
                                if(fab  &&  fabs.is_contained(fab)) {
627
 
                                        fabs.append(fab);
628
 
                                }
629
 
                        }
630
 
                }
631
 
 
632
 
                // are there fabs?
633
 
                const char *fab_base = translator::translate("%s factory %s %s",lang);
634
 
                slist_iterator_tpl<fabrik_t*> fab_iter(fabs);
635
 
                while (fab_iter.next()) {
636
 
                        // with factories
637
 
                        sprintf(buf, fab_base, city_name, translator::translate(fab_iter.get_current()->get_besch()->get_name(),lang), stop );
638
 
                        if(  !all_names.get(buf).is_bound()  ) {
639
 
                                return strdup(buf);
 
645
                                // with factories
 
646
                                buf.printf( fab_base, city_name, fab_iter.get_current()->get_name(), stop );
 
647
                                if(  !all_names.get(buf).is_bound()  ) {
 
648
                                        return strdup(buf);
 
649
                                }
 
650
                                buf.clear();
640
651
                        }
641
652
                }
642
653
 
643
654
                // no fabs or all names used up already
644
 
                // check for other special building (townhall, monument, tourst attraction)
645
 
                for (int i=0; i<24; i++) {
646
 
                        grund_t *gr = welt->lookup_kartenboden( next_building[i] + k);
647
 
                        if(gr==NULL  ||  gr->get_typ()!=grund_t::fundament) {
648
 
                                // no building here
649
 
                                continue;
650
 
                        }
651
 
                        // since closes coordinates are tested first, we do not need to not sort this
652
 
                        const char *building_name = NULL;
653
 
                        const gebaeude_t* gb = gr->find<gebaeude_t>();
654
 
                        if(gb==NULL) {
655
 
                                // field may have foundations but no building
656
 
                                continue;
657
 
                        }
658
 
                        // now we have a building here
659
 
                        if (gb->is_monument()) {
660
 
                                building_name = translator::translate(gb->get_name(),lang);
661
 
                        }
662
 
                        else if (gb->ist_rathaus() ||
663
 
                                gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_land || // land attraction
664
 
                                gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_city) { // town attraction
665
 
                                building_name = make_single_line_string(translator::translate(gb->get_tile()->get_besch()->get_name(),lang), 2);
666
 
                        }
667
 
                        else {
668
 
                                // normal town house => not suitable for naming
669
 
                                continue;
670
 
                        }
671
 
                        // now we have a name: try it
672
 
                        sprintf(buf, translator::translate("%s building %s %s",lang), city_name, building_name, stop );
673
 
                        if(  !all_names.get(buf).is_bound()  ) {
674
 
                                return strdup(buf);
675
 
                        }
 
655
                // is there a translation for buildings defined?
 
656
                const char *building_base_text = "%s building %s %s";
 
657
                const char *building_base = translator::translate(building_base_text,lang);
 
658
                if(  building_base_text != building_base  ) {
 
659
                        // check for other special building (townhall, monument, tourst attraction)
 
660
                        for (int i=0; i<24; i++) {
 
661
                                grund_t *gr = welt->lookup_kartenboden( next_building[i] + k);
 
662
                                if(gr==NULL  ||  gr->get_typ()!=grund_t::fundament) {
 
663
                                        // no building here
 
664
                                        continue;
 
665
                                }
 
666
                                // since closes coordinates are tested first, we do not need to not sort this
 
667
                                const char *building_name = NULL;
 
668
                                const gebaeude_t* gb = gr->find<gebaeude_t>();
 
669
                                if(gb==NULL) {
 
670
                                        // field may have foundations but no building
 
671
                                        continue;
 
672
                                }
 
673
                                // now we have a building here
 
674
                                if (gb->is_monument()) {
 
675
                                        building_name = translator::translate(gb->get_name(),lang);
 
676
                                }
 
677
                                else if (gb->ist_rathaus() ||
 
678
                                        gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_land || // land attraction
 
679
                                        gb->get_tile()->get_besch()->get_utyp() == haus_besch_t::attraction_city) { // town attraction
 
680
                                        building_name = make_single_line_string(translator::translate(gb->get_tile()->get_besch()->get_name(),lang), 2);
 
681
                                }
 
682
                                else {
 
683
                                        // normal town house => not suitable for naming
 
684
                                        continue;
 
685
                                }
 
686
                                // now we have a name: try it
 
687
                                buf.printf( building_base, city_name, building_name, stop );
 
688
                                if(  !all_names.get(buf).is_bound()  ) {
 
689
                                        return strdup(buf);
 
690
                                }
 
691
                                buf.clear();
 
692
                        }
 
693
                }
 
694
 
 
695
                // if there are street names, use them
 
696
                if(  inside  ||  suburb  ) {
 
697
                        buf.clear();
 
698
                        vector_tpl<char *> street_names( translator::get_street_name_list() );
 
699
                        while(  !street_names.empty()  ) {
 
700
                                const uint32 idx = simrand(street_names.get_count());
 
701
 
 
702
                                buf.clear();
 
703
                                buf.printf( street_names[idx], city_name, stop );
 
704
                                if(  !all_names.get(buf).is_bound()  ) {
 
705
                                        return strdup(buf);
 
706
                                }
 
707
                                // esle: remove this entry ...
 
708
                                street_names.remove_at(idx);
 
709
                        }
 
710
                        buf.clear();
676
711
                }
677
712
 
678
713
                // still all names taken => then try the normal naming scheme ...
679
714
                char numbername[10];
680
715
                if(inside) {
681
716
                        strcpy( numbername, "0center" );
682
 
                } else if (li_gr - 6 < k.x  &&  re_gr + 6 > k.x  &&  ob_gr - 6 < k.y  &&  un_gr + 6 > k.y) {
 
717
                } else if(suburb) {
683
718
                        // close to the city we use a different scheme, with suburbs
684
719
                        strcpy( numbername, "0suburb" );
685
720
                }
691
726
                static const char *diagonal_name[4] = { "nordwest", "nordost", "suedost", "suedwest" };
692
727
                static const char *direction_name[4] = { "nord", "ost", "sued", "west" };
693
728
 
 
729
                uint8 const rot = welt->get_settings().get_rotation();
694
730
                if (k.y < ob_gr  ||  (inside  &&  k.y*3 < (un_gr+ob_gr+ob_gr))  ) {
695
731
                        if (k.x < li_gr) {
696
 
                                dirname = diagonal_name[(4-welt->get_einstellungen()->get_rotation())%4];
 
732
                                dirname = diagonal_name[(4 - rot) % 4];
697
733
                        }
698
734
                        else if (k.x > re_gr) {
699
 
                                dirname = diagonal_name[(5-welt->get_einstellungen()->get_rotation())%4];
 
735
                                dirname = diagonal_name[(5 - rot) % 4];
700
736
                        }
701
737
                        else {
702
 
                                dirname = direction_name[(4-welt->get_einstellungen()->get_rotation())%4];
 
738
                                dirname = direction_name[(4 - rot) % 4];
703
739
                        }
704
740
                } else if (k.y > un_gr  ||  (inside  &&  k.y*3 > (un_gr+un_gr+ob_gr))  ) {
705
741
                        if (k.x < li_gr) {
706
 
                                dirname = diagonal_name[(3-welt->get_einstellungen()->get_rotation())%4];
 
742
                                dirname = diagonal_name[(3 - rot) % 4];
707
743
                        }
708
744
                        else if (k.x > re_gr) {
709
 
                                dirname = diagonal_name[(6-welt->get_einstellungen()->get_rotation())%4];
 
745
                                dirname = diagonal_name[(6 - rot) % 4];
710
746
                        }
711
747
                        else {
712
 
                                dirname = direction_name[(6-welt->get_einstellungen()->get_rotation())%4];
 
748
                                dirname = direction_name[(6 - rot) % 4];
713
749
                        }
714
750
                } else {
715
751
                        if (k.x <= stadt->get_pos().x) {
716
 
                                dirname = direction_name[(3-welt->get_einstellungen()->get_rotation())%4];
 
752
                                dirname = direction_name[(3 - rot) % 4];
717
753
                        }
718
754
                        else {
719
 
                                dirname = direction_name[(5-welt->get_einstellungen()->get_rotation())%4];
 
755
                                dirname = direction_name[(5 - rot) % 4];
720
756
                        }
721
757
                }
722
758
                dirname = translator::translate(dirname,lang);
732
768
                                        continue;
733
769
                                }
734
770
                                // allow for names without direction
735
 
                                uint8 count_s = 0;
736
 
                                for(  uint i=0;  base_name[i]!=0;  i++  ) {
737
 
                                        if(  base_name[i]=='%'  &&  base_name[i+1]=='s'  ) {
738
 
                                                i++;
739
 
                                                count_s++;
740
 
                                        }
741
 
                                }
 
771
                                uint8 count_s = count_printf_param( base_name );
742
772
                                if(count_s==3) {
743
773
                                        // ok, try this name, if free ...
744
 
                                        sprintf(buf, base_name, city_name, dirname, stop );
 
774
                                        buf.printf( base_name, city_name, dirname, stop );
745
775
                                }
746
776
                                else {
747
777
                                        // ok, try this name, if free ...
748
 
                                        sprintf(buf, base_name, city_name, stop );
 
778
                                        buf.printf( base_name, city_name, stop );
749
779
                                }
750
780
                                if(  !all_names.get(buf).is_bound()  ) {
751
781
                                        return strdup(buf);
752
782
                                }
 
783
                                buf.clear();
753
784
                        }
754
785
                        // here we did not find a suitable name ...
755
786
                        // ok, no suitable city names, try the suburb ones ...
777
808
 
778
809
        // finally: is there a stop with this name already?
779
810
        for(  uint32 i=1;  i<65536;  i++  ) {
780
 
                sprintf(buf, base_name, city_name, i, stop );
 
811
                buf.printf( base_name, city_name, i, stop );
781
812
                if(  !all_names.get(buf).is_bound()  ) {
782
813
                        return strdup(buf);
783
814
                }
 
815
                buf.clear();
784
816
        }
785
817
 
786
818
        // emergency measure: But before we should run out of handles anyway ...
816
848
 
817
849
 
818
850
 
819
 
bool haltestelle_t::step(sint16 &units_remaining)
 
851
bool haltestelle_t::step(uint8 what, sint16 &units_remaining)
820
852
{
821
 
//      DBG_MESSAGE("haltestelle_t::step()","%s (cnt %i)",get_name(),reroute_counter);
822
 
        if(rebuilt_destination_counter!=welt->get_schedule_counter()) {
823
 
                // schedule has changed ...
824
 
                status_step = RESCHEDULING;
825
 
                units_remaining -= (rebuild_destinations()/256)+2;
826
 
        }
827
 
        else if(reroute_counter!=welt->get_schedule_counter()) {
828
 
                // all new connection updated => recalc routes
829
 
                status_step = REROUTING;
830
 
                if(  !reroute_goods(units_remaining)  ) {
831
 
                        return false;
832
 
                }
833
 
                recalc_status();
834
 
        }
835
 
        else {
836
 
                // nothing needs to be done
837
 
                status_step = 0;
838
 
                units_remaining = 0;
 
853
        switch(what) {
 
854
                case RECONNECTING:
 
855
                        units_remaining -= (rebuild_connections()/256)+2;
 
856
                        break;
 
857
                case REROUTING:
 
858
                        if(  !reroute_goods(units_remaining)  ) {
 
859
                                return false;
 
860
                        }
 
861
                        recalc_status();
 
862
                        break;
 
863
                default:
 
864
                        break;
839
865
        }
840
866
        return true;
841
867
}
849
875
void haltestelle_t::neuer_monat()
850
876
{
851
877
        if(  welt->get_active_player()==besitzer_p  &&  status_color==COL_RED  ) {
852
 
                char buf[256];
853
 
                sprintf(buf, translator::translate("!0_STATION_CROWDED"), get_name());
 
878
                cbuffer_t buf;
 
879
                buf.printf( translator::translate("!0_STATION_CROWDED"), get_name() );
854
880
                welt->get_message()->add_message(buf, get_basis_pos(),message_t::full, PLAYER_FLAG|besitzer_p->get_player_nr(), IMG_LEER );
855
881
                enables &= (PAX|POST|WARE);
856
882
        }
881
907
{
882
908
        if(  last_catg_index==255  ) {
883
909
                last_catg_index = 0;
884
 
                last_ware_index = 0;
885
910
        }
886
911
 
887
912
        for(  ; last_catg_index<warenbauer_t::get_max_catg_index(); last_catg_index++) {
888
913
 
 
914
                if(  units_remaining<=0  ) {
 
915
                        return false;
 
916
                }
 
917
 
889
918
                if(waren[last_catg_index]) {
890
919
 
891
920
                        // first: clean out the array
892
 
                        if(  last_ware_index==0  ) {
893
 
                                vector_tpl<ware_t> * warray = waren[last_catg_index];
894
 
                                vector_tpl<ware_t> * new_warray = new vector_tpl<ware_t>(warray->get_count());
895
 
 
896
 
                                for(  int j=warray->get_count()-1;  j>=0;  j--  ) {
897
 
                                        ware_t & ware = (*warray)[j];
898
 
 
899
 
                                        if(ware.menge==0) {
900
 
                                                continue;
901
 
                                        }
902
 
 
903
 
                                        // since also the factory halt list is added to the ground, we can use just this ...
904
 
                                        if(  welt->lookup(ware.get_zielpos())->is_connected(self)  ) {
905
 
                                                // we are already there!
906
 
                                                if(ware.is_freight()) {
907
 
                                                        liefere_an_fabrik(ware);
908
 
                                                }
909
 
                                                continue;
910
 
                                        }
911
 
 
912
 
                                        // add to new array
913
 
                                        new_warray->append( ware );
914
 
                                }
915
 
 
916
 
                                // delete, if nothing connects here
917
 
                                if(  new_warray->empty()  ) {
918
 
                                        if(  warenziele[last_catg_index].empty()  ) {
919
 
                                                // no connections from here => delete
920
 
                                                delete new_warray;
921
 
                                                new_warray = NULL;
922
 
                                        }
923
 
                                }
924
 
 
925
 
                                // replace the array
926
 
                                delete waren[last_catg_index];
927
 
                                waren[last_catg_index] = new_warray;
928
 
                        }
929
 
 
930
 
                        // if somtehing left
 
921
                        vector_tpl<ware_t> * warray = waren[last_catg_index];
 
922
                        vector_tpl<ware_t> * new_warray = new vector_tpl<ware_t>(warray->get_count());
 
923
 
 
924
                        for(  int j=warray->get_count()-1;  j>=0;  j--  ) {
 
925
                                ware_t & ware = (*warray)[j];
 
926
 
 
927
                                if(ware.menge==0) {
 
928
                                        continue;
 
929
                                }
 
930
 
 
931
                                // since also the factory halt list is added to the ground, we can use just this ...
 
932
                                if(  welt->lookup(ware.get_zielpos())->is_connected(self)  ) {
 
933
                                        // we are already there!
 
934
                                        if(  ware.to_factory  ) {
 
935
                                                liefere_an_fabrik(ware);
 
936
                                        }
 
937
                                        continue;
 
938
                                }
 
939
 
 
940
                                // add to new array
 
941
                                new_warray->append( ware );
 
942
                        }
 
943
 
 
944
                        // delete, if nothing connects here
 
945
                        if(  new_warray->empty()  ) {
 
946
                                if(  connections[last_catg_index].empty()  ) {
 
947
                                        // no connections from here => delete
 
948
                                        delete new_warray;
 
949
                                        new_warray = NULL;
 
950
                                }
 
951
                        }
 
952
 
 
953
                        // replace the array
 
954
                        delete waren[last_catg_index];
 
955
                        waren[last_catg_index] = new_warray;
 
956
 
 
957
                        // if something left
931
958
                        // re-route goods to adapt to changes in world layout,
932
 
                        // remove all goods which destination was removed from the map
933
 
                        if(waren[last_catg_index]  &&  waren[last_catg_index]->get_count()>0) {
934
 
 
935
 
                                vector_tpl<ware_t> * warray = waren[last_catg_index];
936
 
                                while(  last_ware_index<warray->get_count()  ) {
937
 
 
938
 
                                        if(  suche_route( (*warray)[last_ware_index], NULL, false )==NO_ROUTE  ) {
 
959
                        // remove all goods whose destination was removed from the map
 
960
                        if (waren[last_catg_index] && !waren[last_catg_index]->empty()) {
 
961
 
 
962
                                vector_tpl<ware_t> &warray = *waren[last_catg_index];
 
963
                                uint32 last_ware_index = 0;
 
964
                                units_remaining -= warray.get_count();
 
965
                                while(  last_ware_index<warray.get_count()  ) {
 
966
                                        search_route_resumable(warray[last_ware_index]);
 
967
                                        if(  warray[last_ware_index].get_ziel()==halthandle_t()  ) {
939
968
                                                // remove invalid destinations
940
 
                                                warray->remove_at(last_ware_index);
 
969
                                                warray.remove_at(last_ware_index);
941
970
                                        }
942
971
                                        else {
943
 
                                                last_ware_index++;
944
 
                                        }
945
 
                                        // break after a certain number of reroute actions
946
 
                                        if(  --units_remaining==0  ) {
947
 
                                                return false;
 
972
                                                ++last_ware_index;
948
973
                                        }
949
974
                                }
950
 
                                // now we are finisched with this array
951
 
                                // => reset last_ware_index for the next categorie
952
975
                        }
953
976
                }
954
 
 
955
 
                last_ware_index = 0;
956
977
        }
957
978
        // likely the display must be updated after this
958
979
        resort_freight_info = true;
959
980
        last_catg_index = 255;  // all categories are rerouted
960
 
        reroute_counter = welt->get_schedule_counter(); // no need to reroute further
961
981
        return true;    // all updated ...
962
982
}
963
983
 
980
1000
                grund_t* gb = i->grund;
981
1001
                koord p = gb->get_pos().get_2d();
982
1002
 
983
 
                int cov = welt->get_einstellungen()->get_station_coverage();
 
1003
                int const cov = welt->get_settings().get_station_coverage();
984
1004
                vector_tpl<fabrik_t*>& fablist = fabrik_t::sind_da_welche(welt, p - koord(cov, cov), p + koord(cov, cov));
985
1005
                for(unsigned i=0; i<fablist.get_count(); i++) {
986
1006
                        fabrik_t* fab = fablist[i];
1003
1023
}
1004
1024
 
1005
1025
 
1006
 
 
1007
 
// only needed for rebuild_destinations(), but mingw hickup on local classes
1008
 
class warenzielsorter_t {
1009
 
public:
1010
 
        halthandle_t halt;
1011
 
        uint8 stops;
1012
 
        uint8 catg_index;
1013
 
 
1014
 
        warenzielsorter_t( halthandle_t h, uint8 s, uint8 ci ) :
1015
 
                halt(h),
1016
 
                stops(s),
1017
 
                catg_index(ci)
1018
 
                {}
1019
 
        warenzielsorter_t() { stops=0; catg_index=0; }
1020
 
        inline bool operator == (const warenzielsorter_t &k) const {
1021
 
                return halt==k.halt  &&  stops<=k.stops  &&  catg_index==k.catg_index;
1022
 
        }
1023
 
};
1024
 
 
1025
1026
/**
1026
 
 * Rebuilds the list of reachable destinations
1027
 
 * returns the number of stops considered for this
1028
 
 * The warenziele are sorted by nubmer of intermediate stops; next are first
 
1027
 * Rebuilds the list of connections to directly reachable halts
 
1028
 * Returns the number of stops considered
1029
1029
 * @author Hj. Malthaner
1030
1030
 */
1031
 
sint32 haltestelle_t::rebuild_destinations()
 
1031
#define WEIGHT_WAIT (8)
 
1032
#define WEIGHT_HALT (1)
 
1033
// the minimum weight of a connection from a transfer halt
 
1034
#define WEIGHT_MIN (WEIGHT_WAIT+WEIGHT_HALT)
 
1035
sint32 haltestelle_t::rebuild_connections()
1032
1036
{
1033
1037
        // Hajo: first, remove all old entries
1034
1038
        for(  uint8 i=0;  i<warenbauer_t::get_max_catg_index();  i++  ){
1035
 
                warenziele[i].clear();
1036
 
                non_identical_schedules[i] = 0;
 
1039
                connections[i].clear();
 
1040
                serving_schedules[i] = 0;
1037
1041
        }
1038
 
        rebuilt_destination_counter = welt->get_schedule_counter();
1039
 
        reroute_counter = rebuilt_destination_counter-1;
1040
1042
        resort_freight_info = true;     // might result in error in routing
1041
1043
 
1042
1044
        last_catg_index = 255;  // must reroute everything
1043
1045
        sint32 connections_searched = 0;
1044
1046
 
1045
 
        vector_tpl<warenzielsorter_t> warenziele_by_stops;
1046
 
 
1047
1047
// DBG_MESSAGE("haltestelle_t::rebuild_destinations()", "Adding new table entries");
1048
1048
 
1049
 
        // since per schedule the non_identical_schedules counter must be incremented only once to identify transfer stops (which have >1):
1050
 
        uint8 non_identical_schedules_flag[256];
1051
 
        MEMZERON(non_identical_schedules_flag, warenbauer_t::get_max_catg_index());
 
1049
        // since per schedule the serving_schedules counter must be incremented only once to identify transfer stops (which have >1):
 
1050
        uint8 suitable_halt_found[256];
 
1051
        MEMZERON(suitable_halt_found, warenbauer_t::get_max_catg_index());
1052
1052
 
1053
1053
        const spieler_t *owner;
1054
1054
        schedule_t *fpl;
1106
1106
                        }
1107
1107
                }
1108
1108
 
1109
 
                if (  supported_catg_index.get_count()==0  ) {
 
1109
                if (supported_catg_index.empty()) {
1110
1110
                        // this halt does not support the goods categories handled by the line/lineless convoy
1111
1111
                        continue;
1112
1112
                }
1114
1114
                INT_CHECK("simhalt.cc 612");
1115
1115
 
1116
1116
                // now we add the schedule to the connection array
1117
 
                uint8 stop_count = 0; // Measures the distance to "self".
1118
 
                for(  uint8 j=1;  j<fpl->get_count();  j++  ) {
1119
 
 
1120
 
                        halthandle_t halt = get_halt(welt, fpl->eintrag[(first_self_index+j)%fpl->get_count()].pos,owner);
1121
 
                        if(  !halt.is_bound()  ) {
1122
 
                                continue;
1123
 
                        }
1124
 
                        if(  halt==self  ) {
1125
 
                                stop_count = 0;
1126
 
                                continue;
1127
 
                        }
1128
 
 
1129
 
                        ++stop_count;
1130
 
 
1131
 
                        for(  uint8 ctg=0;  ctg<supported_catg_index.get_count();  ctg ++  ) {
 
1117
                uint16 aggregate_weight = WEIGHT_WAIT;
 
1118
                for(  uint8 j=1;  j<fpl->get_count();  ++j  ) {
 
1119
 
 
1120
                        halthandle_t current_halt = get_halt(welt, fpl->eintrag[(first_self_index+j)%fpl->get_count()].pos,owner);
 
1121
                        if(  !current_halt.is_bound()  ) {
 
1122
                                // ignore way points
 
1123
                                continue;
 
1124
                        }
 
1125
                        if(  current_halt==self  ) {
 
1126
                                // reset aggregate weight
 
1127
                                aggregate_weight = WEIGHT_WAIT;
 
1128
                                continue;
 
1129
                        }
 
1130
 
 
1131
                        aggregate_weight += WEIGHT_HALT;
 
1132
 
 
1133
                        for(  uint8 ctg=0;  ctg<supported_catg_index.get_count();  ++ctg  ) {
1132
1134
                                const uint8 catg_index = supported_catg_index[ctg];
1133
 
                                if(  halt->is_enabled(catg_index)  ) {
1134
 
                                        warenzielsorter_t wzs( halt, stop_count, catg_index );
1135
 
                                        // might be a new halt to add
1136
 
                                        if(  !warenziele_by_stops.is_contained(wzs)  ) {
1137
 
                                                warenziele_by_stops.append(wzs);
1138
 
                                                non_identical_schedules_flag[catg_index] = true;
 
1135
                                if(  current_halt->is_enabled(catg_index)  ) {
 
1136
                                        // there is at least a reachable halt served by this schedule and supporting this goods category
 
1137
                                        suitable_halt_found[catg_index] = true;
 
1138
 
 
1139
                                        // either add a new connection or update the weight of an existing connection where necessary
 
1140
                                        connection_t *const existing_connection = connections[catg_index].insert_unique_ordered( connection_t( current_halt, aggregate_weight ), connection_t::compare );
 
1141
                                        if(  existing_connection  &&  aggregate_weight<existing_connection->weight  ) {
 
1142
                                                existing_connection->weight = aggregate_weight;
1139
1143
                                        }
1140
1144
                                }
1141
1145
                        }
1142
1146
                }
1143
1147
 
1144
 
                for(  uint8 ctg=0;  ctg<supported_catg_index.get_count();  ctg ++  ) {
 
1148
                for(  uint8 ctg=0;  ctg<supported_catg_index.get_count();  ++ctg  ) {
1145
1149
                        const uint8 catg_index = supported_catg_index[ctg];
1146
 
                        if(  non_identical_schedules_flag[catg_index]  ) {
1147
 
                                non_identical_schedules_flag[catg_index] = false;
1148
 
                                if(  non_identical_schedules[catg_index] < 255  ) {
1149
 
                                        // added additional stops => might be transfer stop
1150
 
                                        non_identical_schedules[catg_index]++;
 
1150
                        if(  suitable_halt_found[catg_index]  ) {
 
1151
                                suitable_halt_found[catg_index] = false;
 
1152
                                if(  serving_schedules[catg_index]<255  ) {
 
1153
                                        serving_schedules[catg_index]++;
1151
1154
                                }
1152
1155
                        }
1153
1156
                }
1154
1157
                connections_searched += fpl->get_count();
1155
1158
        }
1156
 
 
1157
 
        // now add them to warenziele ...
1158
 
        uint32 processed_entries = 0;
1159
 
        uint8 stops = 1;
1160
 
        while(  processed_entries<warenziele_by_stops.get_count() ) {
1161
 
                for(  uint32 i=processed_entries;  i<warenziele_by_stops.get_count();  i++  ) {
1162
 
 
1163
 
                        if(  warenziele_by_stops[i].stops==stops  ) {
1164
 
                                vector_tpl<halthandle_t> &wz_list = warenziele[ warenziele_by_stops[i].catg_index ];
1165
 
                                // this test is needed, since the same halt may be added earlier, since it came first in another schedule
1166
 
                                if(  !wz_list.is_contained( warenziele_by_stops[i].halt )  ) {
1167
 
                                        wz_list.append( warenziele_by_stops[i].halt );
1168
 
                                        if(  waren[ warenziele_by_stops[i].catg_index ] == NULL  ) {
1169
 
                                                // indicates that this can route those goods
1170
 
                                                waren[ warenziele_by_stops[i].catg_index ] = new vector_tpl<ware_t>(0);
1171
 
                                        }
1172
 
                                }
1173
 
                                // after processing, current entry becomes useless
1174
 
                                //              --> overwrite it with an unprocessed entry where necessary
1175
 
                                if ( i != processed_entries ) {
1176
 
                                        warenziele_by_stops[i] = warenziele_by_stops[processed_entries];
1177
 
                                }
1178
 
                                ++processed_entries;
1179
 
                        }
1180
 
                }
1181
 
                ++stops;
1182
 
        }
1183
1159
        return connections_searched;
1184
1160
}
1185
1161
 
1186
1162
 
1187
 
 
1188
 
/* HNode is used for route search */
1189
 
struct HNode {
1190
 
        halthandle_t halt;
1191
 
        uint16 depth;
1192
 
        HNode *link;
1193
 
};
1194
 
 
 
1163
/**
 
1164
 * Data for route searching
 
1165
 */
 
1166
haltestelle_t::halt_data_t haltestelle_t::halt_data[65536];
 
1167
binary_heap_tpl<haltestelle_t::route_node_t> haltestelle_t::open_list;
 
1168
uint8 haltestelle_t::markers[65536];
 
1169
uint8 haltestelle_t::current_marker = 0;
 
1170
/**
 
1171
 * Data for resumable route search
 
1172
 */
 
1173
halthandle_t haltestelle_t::last_search_origin;
 
1174
uint8 haltestelle_t::last_search_ware_catg_idx = 255;
1195
1175
/**
1196
1176
 * This routine tries to find a route for a good packet (ware)
1197
1177
 * it will be called for
1209
1189
 * if USE_ROUTE_SLIST_TPL is defined, the list template will be used.
1210
1190
 * However, this is about 50% slower.
1211
1191
 *
1212
 
 * @author Hj. Malthaner/prissi/gerw
 
1192
 * @author Hj. Malthaner/prissi/gerw/Knightly
1213
1193
 */
1214
 
int haltestelle_t::suche_route( ware_t &ware, koord *next_to_ziel, const bool no_routing_over_overcrowding )
 
1194
int haltestelle_t::search_route( const halthandle_t *const start_halts, const uint16 start_halt_count, const bool no_routing_over_overcrowding, ware_t &ware, ware_t *const return_ware )
1215
1195
{
1216
 
        const ware_besch_t * warentyp = ware.get_besch();
1217
 
        const uint8 ware_catg_index = warentyp->get_catg_index();
1218
 
        const koord ziel = ware.get_zielpos();
 
1196
        const uint8 ware_catg_idx = ware.get_besch()->get_catg_index();
1219
1197
 
1220
1198
        // since also the factory halt list is added to the ground, we can use just this ...
1221
 
        const planquadrat_t *plan = welt->lookup(ziel);
1222
 
        const halthandle_t *halt_list = plan->get_haltlist();
 
1199
        const planquadrat_t *const plan = welt->lookup( ware.get_zielpos() );
 
1200
        const halthandle_t *const halt_list = plan->get_haltlist();
1223
1201
        // but we can only use a subset of these
1224
 
        vector_tpl<halthandle_t> ziel_list(plan->get_haltlist_count());
1225
 
        for( unsigned h=0;  h<plan->get_haltlist_count();  h++ ) {
 
1202
        static vector_tpl<halthandle_t> end_halts(16);
 
1203
        end_halts.clear();
 
1204
        for( uint32 h=0;  h<plan->get_haltlist_count();  ++h ) {
1226
1205
                halthandle_t halt = halt_list[h];
1227
 
                if(  halt->is_enabled(warentyp)  ) {
1228
 
                        ziel_list.append(halt);
1229
 
                }
1230
 
                else {
1231
 
//DBG_MESSAGE("suche_route()","halt %s near (%i,%i) does not accept  %s!",halt->get_name(),ziel.x,ziel.y,warentyp->get_name());
 
1206
                if(  halt.is_bound()  &&  halt->is_enabled(ware_catg_idx)  ) {
 
1207
                        // check if this is present in the list of start halts
 
1208
                        for(  uint16 s=0;  s<start_halt_count;  ++s  ) {
 
1209
                                if(  halt==start_halts[s]  ) {
 
1210
                                        // destination halt is also a start halt -> within walking distance
 
1211
                                        ware.set_ziel( start_halts[s] );
 
1212
                                        ware.set_zwischenziel( halthandle_t() );
 
1213
                                        if(  return_ware  ) {
 
1214
                                                return_ware->set_ziel( start_halts[s] );
 
1215
                                                return_ware->set_zwischenziel( halthandle_t() );
 
1216
                                        }
 
1217
                                        return ROUTE_WALK;
 
1218
                                }
 
1219
                        }
 
1220
                        end_halts.append(halt);
1232
1221
                }
1233
1222
        }
1234
1223
 
1235
 
        if(  ziel_list.empty()  ) {
1236
 
                //no target station found
 
1224
        if(  end_halts.empty()  ) {
 
1225
                // no end halt found
1237
1226
                ware.set_ziel( halthandle_t() );
1238
1227
                ware.set_zwischenziel( halthandle_t() );
1239
 
                // printf("keine route zu %d,%d nach %d steps\n", ziel.x, ziel.y, step);
1240
 
                if(  next_to_ziel != NULL  ) {
1241
 
                        *next_to_ziel = koord::invalid;
 
1228
                if(  return_ware  ) {
 
1229
                        return_ware->set_ziel( halthandle_t() );
 
1230
                        return_ware->set_zwischenziel( halthandle_t() );
1242
1231
                }
1243
1232
                return NO_ROUTE;
1244
1233
        }
1245
 
 
1246
 
        // check, if the shortest connection is not right to us ...
1247
 
        if(  ziel_list.is_contained(self)  ) {
1248
 
                ware.set_ziel( self );
1249
 
                ware.set_zwischenziel( halthandle_t() );
1250
 
                if(  next_to_ziel != NULL  ) {
1251
 
                        *next_to_ziel = koord::invalid;
1252
 
                }
1253
 
                return ROUTE_OK;
1254
 
        }
1255
 
 
1256
 
        // set curretn marker
1257
 
        current_mark ++;
1258
 
        if(  current_mark==0  ) {
 
1234
        // invalidate search history
 
1235
        last_search_origin = halthandle_t();
 
1236
 
 
1237
        // set current marker
 
1238
        ++current_marker;
 
1239
        if(  current_marker==0  ) {
1259
1240
                MEMZERON(markers, halthandle_t::get_size());
1260
 
                current_mark = 1;
1261
 
        }
1262
 
 
1263
 
        // single threading makes some things easier
1264
 
        static HNode nodes[32768];
1265
 
 
1266
 
        // die Berechnung erfolgt durch eine Breitensuche fuer Graphen
1267
 
        // Warteschlange fuer Breitensuche
1268
 
        const uint16 max_transfers = welt->get_einstellungen()->get_max_transfers();
1269
 
#ifdef USE_ROUTE_SLIST_TPL
1270
 
        slist_tpl<HNode *> queue;
1271
 
#else
1272
 
        // we need just need to know the current bottom of the list with respect to the nodes array
1273
 
        uint32 progress_pointer = 0;
1274
 
#endif
1275
 
        uint32 allocation_pointer = 1;
1276
 
        HNode *current_node;
1277
 
        HNode *new_node;
1278
 
 
1279
 
        nodes[0].halt = self;
1280
 
        nodes[0].link = NULL;
1281
 
        nodes[0].depth = 0;
1282
 
 
1283
 
#ifdef USE_ROUTE_SLIST_TPL
1284
 
        queue.insert( &nodes[0] );      // init queue mit erstem feld
1285
 
#endif
1286
 
        markers[ self.get_id() ] = current_mark;
1287
 
 
1288
 
        const uint32 max_hops = welt->get_einstellungen()->get_max_hops();
 
1241
                current_marker = 1u;
 
1242
        }
 
1243
 
 
1244
        // initialisations for end halts => save some checking inside search loop
 
1245
        for(  uint32 e=0;  e<end_halts.get_count();  ++e  ) {
 
1246
                const uint16 halt_id = end_halts[e].get_id();
 
1247
                halt_data[ halt_id ].best_weight = 65535u;
 
1248
                halt_data[ halt_id ].destination = 1u;
 
1249
                markers[ halt_id ] = current_marker;
 
1250
        }
 
1251
 
 
1252
        uint16 const max_transfers = welt->get_settings().get_max_transfers();
 
1253
        uint16 const max_hops      = welt->get_settings().get_max_hops();
 
1254
        uint16 allocation_pointer = 0;
 
1255
        uint16 best_destination_weight = 65535u;                // best weight among all destinations
 
1256
 
 
1257
        open_list.clear();
 
1258
 
 
1259
        // initialise the origin node(s)
 
1260
        for(  ;  allocation_pointer<start_halt_count;  ++allocation_pointer  ) {
 
1261
                halthandle_t start_halt = start_halts[allocation_pointer];
 
1262
 
 
1263
                open_list.insert( route_node_t(start_halt, 0) );
 
1264
 
 
1265
                halt_data_t & start_data = halt_data[ start_halt.get_id() ];
 
1266
                start_data.best_weight = 65535u;
 
1267
                start_data.destination = 0;
 
1268
                start_data.depth       = 0;
 
1269
                start_data.transfer    = halthandle_t();
 
1270
 
 
1271
                markers[ start_halt.get_id() ] = current_marker;
 
1272
        }
 
1273
 
1289
1274
        // here the normal routing with overcrowded stops is done
1290
1275
        do {
1291
 
#ifdef USE_ROUTE_SLIST_TPL
1292
 
                tmp = queue.remove_first();
1293
 
#else
1294
 
                current_node = &nodes[progress_pointer++];
1295
 
#endif
1296
 
 
1297
 
                // Hajo: check for max transfers -> don't add more stations
1298
 
                //       to queue if the limit is reached
1299
 
                if( current_node->depth < max_transfers ) {
1300
 
                        const vector_tpl<halthandle_t> &wz = current_node->halt->warenziele[ware_catg_index];
1301
 
                        for(  uint32 i=0;  i<wz.get_count();  i++  ) {
1302
 
 
1303
 
                                // since these are precalculated, they should be always pointing to a valid ground
1304
 
                                // (if not, we were just under construction, and will be fine after 16 steps)
1305
 
                                const halthandle_t &reachable_halt = wz[i];
1306
 
                                if(  markers[ reachable_halt.get_id() ]<current_mark  &&  reachable_halt.is_bound()  ) {
1307
 
 
1308
 
                                        // betretene Haltestellen markieren
1309
 
                                        markers[ reachable_halt.get_id() ] = current_mark;
1310
 
 
1311
 
                                        // Knightly : Only transfer halts and destination halt are added to the HNode array
1312
 
                                        if(  ziel_list.is_contained(reachable_halt)  ) {
1313
 
                                                // Case : Destination found
1314
 
                                                new_node = &nodes[allocation_pointer++];
1315
 
                                                new_node->halt = reachable_halt;
1316
 
                                                // Knightly : node depth will not be used afterwards, so no need to assign a value
1317
 
                                                // new_node->depth = current_node->depth + 1;
1318
 
                                                new_node->link = current_node;
1319
 
#ifdef USE_ROUTE_SLIST_TPL
1320
 
                                                queue.append( new_node );
1321
 
#endif
1322
 
                                                current_node = new_node;
1323
 
                                                goto found;
1324
 
                                        }
1325
 
                                        else if(  reachable_halt->non_identical_schedules[ware_catg_index] > 1  &&  allocation_pointer < 32000u  ) {
1326
 
                                                // Case : Transfer halt
1327
 
                                                new_node = &nodes[allocation_pointer++];
1328
 
                                                new_node->halt = reachable_halt;
1329
 
                                                new_node->depth = current_node->depth + 1;
1330
 
                                                new_node->link = current_node;
1331
 
#ifdef USE_ROUTE_SLIST_TPL
1332
 
                                                queue.append( new_node );
1333
 
#endif
1334
 
                                        }
1335
 
                                }
1336
 
                        }
1337
 
                } // max transfers
1338
 
 
1339
 
#ifdef USE_ROUTE_SLIST_TPL
1340
 
        } while (!queue.empty() && progress_pointer < max_hops);
1341
 
#else
1342
 
        } while(  progress_pointer < allocation_pointer  &&  progress_pointer < max_hops  );
1343
 
#endif
 
1276
                route_node_t current_node = open_list.pop();
 
1277
                // do not use aggregate_weight as it is _not_ the weight of the current_node
 
1278
                // there might be a heuristic weight added
 
1279
 
 
1280
                const uint16 current_halt_id = current_node.halt.get_id();
 
1281
                halt_data_t & current_halt_data = halt_data[ current_halt_id ];
 
1282
 
 
1283
                if(  current_halt_data.destination  ) {
 
1284
                        // destination found
 
1285
                        ware.set_ziel( current_node.halt );
 
1286
                        assert(current_halt_data.transfer.get_id() != 0);
 
1287
                        if(  return_ware  ) {
 
1288
                                // next transfer for the reverse route
 
1289
                                // if the end halt and its connections contain more than one transfer halt then
 
1290
                                // the transfer halt may not be the last transfer of the forward route
 
1291
                                // (the rerouting will happen in haltestelle_t::hole_ab)
 
1292
                                return_ware->set_zwischenziel(current_halt_data.transfer);
 
1293
                                const vector_tpl<connection_t> &conns = current_node.halt->connections[ware_catg_idx];
 
1294
                                // count the connected transfer halts (including end halt)
 
1295
                                uint8 t = current_node.halt->serving_schedules[ware_catg_idx] > 1;
 
1296
                                for(  uint32 i=0; t<=1  &&  i<conns.get_count();  ++i  ) {
 
1297
                                        t += conns[i].halt.is_bound() && conns[i].halt->serving_schedules[ware_catg_idx] > 1;
 
1298
                                }
 
1299
                                return_ware->set_zwischenziel(  t<=1  ?  current_halt_data.transfer  : halthandle_t());
 
1300
                        }
 
1301
                        // find the next transfer
 
1302
                        bool via_overcrowded_transfer = false;
 
1303
                        halthandle_t transfer_halt = current_node.halt;
 
1304
                        if(  no_routing_over_overcrowding  ) {
 
1305
                                while(  halt_data[ transfer_halt.get_id() ].depth > 1   ) {
 
1306
                                        transfer_halt = halt_data[ transfer_halt.get_id() ].transfer;
 
1307
                                        if(  !via_overcrowded_transfer  &&  transfer_halt->is_overcrowded(ware_catg_idx)  ) {
 
1308
                                                via_overcrowded_transfer = true;
 
1309
                                        }
 
1310
                                }
 
1311
                        }
 
1312
                        else {
 
1313
                                while(  halt_data[ transfer_halt.get_id() ].depth > 1   ) {
 
1314
                                        transfer_halt = halt_data[ transfer_halt.get_id() ].transfer;
 
1315
                                }
 
1316
                        }
 
1317
                        ware.set_zwischenziel(transfer_halt);
 
1318
                        if(  return_ware  ) {
 
1319
                                // return ware's destination halt is the start halt of the forward trip
 
1320
                                assert( halt_data[ transfer_halt.get_id() ].transfer.get_id() );
 
1321
                                return_ware->set_ziel( halt_data[ transfer_halt.get_id() ].transfer );
 
1322
                        }
 
1323
                        return via_overcrowded_transfer ? ROUTE_OVERCROWDED : ROUTE_OK;
 
1324
                }
 
1325
 
 
1326
                // check if the current halt is already in closed list
 
1327
                if(  current_halt_data.best_weight==0  ) {
 
1328
                        // shortest path to the current halt has already been found earlier
 
1329
                        continue;
 
1330
                }
 
1331
 
 
1332
                if(  current_halt_data.depth > max_transfers  ) {
 
1333
                        // maximum transfer limit is reached -> do not add reachable halts to open list
 
1334
                        continue;
 
1335
                }
 
1336
 
 
1337
                const vector_tpl<connection_t> &conns = current_node.halt->connections[ware_catg_idx];
 
1338
                for(  uint32 i=0;  i<conns.get_count();  ++i  ) {
 
1339
 
 
1340
                        // since these are precalculated, they should be always pointing to a valid ground
 
1341
                        // (if not, we were just under construction, and will be fine after 16 steps)
 
1342
                        const connection_t &current_conn = conns[i];
 
1343
 
 
1344
                        const uint16 reachable_halt_id = current_conn.halt.get_id();
 
1345
 
 
1346
                        if(  markers[ reachable_halt_id ]!=current_marker  ) {
 
1347
                                // Case : not processed before
 
1348
 
 
1349
                                // indicate that this halt has been processed
 
1350
                                markers[ reachable_halt_id ] = current_marker;
 
1351
 
 
1352
                                if(  current_conn.halt.is_bound()  &&  current_conn.halt->serving_schedules[ware_catg_idx]>1u  &&  allocation_pointer<max_hops  ) {
 
1353
                                        // Case : transfer halt
 
1354
                                        const uint16 total_weight = current_halt_data.best_weight + current_conn.weight;
 
1355
 
 
1356
                                        if(  total_weight < best_destination_weight  ) {
 
1357
 
 
1358
                                                halt_data[ reachable_halt_id ].best_weight = total_weight;
 
1359
                                                halt_data[ reachable_halt_id ].destination = 0;
 
1360
                                                halt_data[ reachable_halt_id ].depth       = current_halt_data.depth + 1u;
 
1361
                                                halt_data[ reachable_halt_id ].transfer    = current_node.halt;
 
1362
 
 
1363
                                                allocation_pointer++;
 
1364
                                                // as the next halt is not a destination add WEIGHT_MIN
 
1365
                                                open_list.insert( route_node_t(current_conn.halt, total_weight + WEIGHT_MIN) );
 
1366
                                        }
 
1367
                                        else {
 
1368
                                                // Case: non-optimal transfer halt -> put in closed list
 
1369
                                                halt_data[ reachable_halt_id ].best_weight = 0;
 
1370
                                        }
 
1371
                                }
 
1372
                                else {
 
1373
                                        // Case: halt is removed / no transfer halt -> put in closed list
 
1374
                                        halt_data[ reachable_halt_id ].best_weight = 0;
 
1375
                                }
 
1376
 
 
1377
                        }       // if not processed before
 
1378
                        else if(  halt_data[ reachable_halt_id ].best_weight!=0  ) {
 
1379
                                // Case : processed before but not in closed list : that is, in open list
 
1380
                                //                      --> can only be destination halt or transfer halt
 
1381
 
 
1382
                                uint16 total_weight = current_halt_data.best_weight + current_conn.weight;
 
1383
 
 
1384
                                if(  total_weight<halt_data[ reachable_halt_id ].best_weight  &&  total_weight<best_destination_weight  &&  allocation_pointer<max_hops  ) {
 
1385
                                        // new weight is lower than lowest weight --> create new node and update halt data
 
1386
 
 
1387
                                        halt_data[ reachable_halt_id ].best_weight = total_weight;
 
1388
                                        // no need to update destination, as halt nature (as destination or transfer) will not change
 
1389
                                        halt_data[ reachable_halt_id ].depth       = current_halt_data.depth + 1u;
 
1390
                                        halt_data[ reachable_halt_id ].transfer    = current_node.halt;
 
1391
 
 
1392
                                        if (halt_data[ reachable_halt_id ].destination) {
 
1393
                                                best_destination_weight = total_weight;
 
1394
                                        }
 
1395
                                        else {
 
1396
                                                // as the next halt is not a destination add WEIGHT_MIN
 
1397
                                                total_weight += WEIGHT_MIN;
 
1398
                                        }
 
1399
 
 
1400
                                        allocation_pointer++;
 
1401
                                        open_list.insert( route_node_t(current_conn.halt, total_weight) );
 
1402
                                }
 
1403
                        }       // else if not in closed list
 
1404
                }       // for each connection entry
 
1405
 
 
1406
                // indicate that the current halt is in closed list
 
1407
                current_halt_data.best_weight = 0;
 
1408
 
 
1409
        } while(  !open_list.empty()  );
1344
1410
 
1345
1411
        // if the loop ends, nothing was found
1346
 
        current_node = NULL;
1347
 
 
1348
 
found:
1349
 
 
1350
 
        if(current_node) {
1351
 
                // ziel gefunden
1352
 
                ware.set_ziel( current_node->halt );
1353
 
 
1354
 
                assert(current_node->link != NULL);
1355
 
 
1356
 
                if(next_to_ziel!=NULL) {
1357
 
                        // for reverse route the next hop
1358
 
                        *next_to_ziel = current_node->link->halt->get_basis_pos();
1359
 
                }
1360
 
                // find the intermediate stops
1361
 
                while(current_node->link->link) {
1362
 
                        current_node = current_node->link;
1363
 
                        if(  no_routing_over_overcrowding  &&  current_node->halt->is_overcrowded(ware_catg_index)  ) {
1364
 
                                return ROUTE_OVERCROWDED;
1365
 
                        }
1366
 
                }
1367
 
                ware.set_zwischenziel(current_node->halt);
1368
 
                return ROUTE_OK;
1369
 
        }
1370
 
        else {
1371
 
                // no suitable target station found
1372
 
                ware.set_ziel( halthandle_t() );
1373
 
                ware.set_zwischenziel( halthandle_t() );
1374
 
                if(next_to_ziel!=NULL) {
1375
 
                        *next_to_ziel = koord::invalid;
1376
 
                }
1377
 
                return NO_ROUTE;
1378
 
        }
1379
 
}
1380
 
 
 
1412
        ware.set_ziel( halthandle_t() );
 
1413
        ware.set_zwischenziel( halthandle_t() );
 
1414
        if(  return_ware  ) {
 
1415
                return_ware->set_ziel( halthandle_t() );
 
1416
                return_ware->set_zwischenziel( halthandle_t() );
 
1417
        }
 
1418
        return NO_ROUTE;
 
1419
}
 
1420
 
 
1421
 
 
1422
void haltestelle_t::search_route_resumable(  ware_t &ware   )
 
1423
{
 
1424
        const uint8 ware_catg_idx = ware.get_besch()->get_catg_index();
 
1425
 
 
1426
        // continue search if start halt and good category did not change
 
1427
        const bool resume_search = last_search_origin == self  &&  ware_catg_idx == last_search_ware_catg_idx;
 
1428
 
 
1429
        if (!resume_search) {
 
1430
                last_search_origin = self;
 
1431
                last_search_ware_catg_idx = ware_catg_idx;
 
1432
                // set current marker
 
1433
                ++current_marker;
 
1434
                if(  current_marker==0  ) {
 
1435
                        MEMZERON(markers, halthandle_t::get_size());
 
1436
                        current_marker = 1u;
 
1437
                }
 
1438
        }
 
1439
 
 
1440
        // remember destination nodes, to reset them before returning
 
1441
        static vector_tpl<uint16> dest_indices(16);
 
1442
        dest_indices.clear();
 
1443
 
 
1444
        uint16 best_destination_weight = 65535u;
 
1445
 
 
1446
        // reset next transfer and destination halt to null -> if they remain null after search, no route can be found
 
1447
        ware.set_ziel( halthandle_t() );
 
1448
        ware.set_zwischenziel( halthandle_t() );
 
1449
        // find suitable destination halts for the ware packet's target position
 
1450
        const planquadrat_t *const plan = welt->lookup( ware.get_zielpos() );
 
1451
        const halthandle_t *const halt_list = plan->get_haltlist();
 
1452
 
 
1453
        // check halt list for presence of current halt
 
1454
        for( uint8 h = 0;  h<plan->get_haltlist_count(); ++h  ) {
 
1455
                if (halt_list[h] == self) {
 
1456
                        // a destination halt is the same as the current halt -> no route searching is necessary
 
1457
                        ware.set_ziel( self );
 
1458
                        return;
 
1459
                }
 
1460
        }
 
1461
 
 
1462
        // check explored connection
 
1463
        if (resume_search) {
 
1464
                for( uint8 h=0;  h<plan->get_haltlist_count();  ++h  ) {
 
1465
                        const halthandle_t halt = halt_list[h];
 
1466
                        if (markers[ halt.get_id() ]==current_marker  &&  halt_data[ halt.get_id() ].best_weight < best_destination_weight  &&  halt.is_bound()) {
 
1467
                                best_destination_weight = halt_data[ halt.get_id() ].best_weight;
 
1468
                                ware.set_ziel( halt );
 
1469
                                ware.set_zwischenziel( halt_data[ halt.get_id() ].transfer );
 
1470
                        }
 
1471
                }
 
1472
                // for all halts with halt_data.weight < explored_weight one of the best routes is found
 
1473
                const uint16 explored_weight = open_list.empty()  ? 65535u : open_list.front().aggregate_weight;
 
1474
 
 
1475
                if (best_destination_weight <= explored_weight) {
 
1476
                        // we explored best route to this destination in last run
 
1477
                        // (any other not yet explored connection will have larger weight)
 
1478
                        // no need to search route for this ware
 
1479
                        return;
 
1480
                }
 
1481
        }
 
1482
        // find suitable destination halt(s), if any
 
1483
        for( uint8 h=0;  h<plan->get_haltlist_count();  ++h  ) {
 
1484
                const halthandle_t halt = halt_list[h];
 
1485
                if(  halt.is_bound()  &&  halt->is_enabled(ware_catg_idx)  ) {
 
1486
                        // initialisations for destination halts => save some checking inside search loop
 
1487
                        if(  markers[ halt.get_id() ]!=current_marker  ) {
 
1488
                                // first time -> initialise marker and all halt data
 
1489
                                markers[ halt.get_id() ] = current_marker;
 
1490
                                halt_data[ halt.get_id() ].best_weight = 65535u;
 
1491
                                halt_data[ halt.get_id() ].destination = true;
 
1492
                        }
 
1493
                        else {
 
1494
                                // initialised before -> only update destination bit set
 
1495
                                halt_data[ halt.get_id() ].destination = true;
 
1496
                        }
 
1497
                        dest_indices.append(halt.get_id());
 
1498
                }
 
1499
        }
 
1500
 
 
1501
        if(  dest_indices.empty()  ) {
 
1502
                // no destination halt found or current halt is the same as (all) the destination halt(s)
 
1503
                return;
 
1504
        }
 
1505
 
 
1506
        uint16 const max_transfers = welt->get_settings().get_max_transfers();
 
1507
        uint16 const max_hops      = welt->get_settings().get_max_hops();
 
1508
 
 
1509
        static uint16 allocation_pointer;
 
1510
        if (!resume_search) {
 
1511
                open_list.clear();
 
1512
 
 
1513
                // initialise the origin node
 
1514
                allocation_pointer = 1u;
 
1515
                open_list.insert( route_node_t(self, 0) );
 
1516
 
 
1517
                halt_data_t & start_data = halt_data[ self.get_id() ];
 
1518
                start_data.best_weight = 0;
 
1519
                start_data.destination = 0;
 
1520
                start_data.depth       = 0;
 
1521
                start_data.transfer    = halthandle_t();
 
1522
 
 
1523
                markers[ self.get_id() ] = current_marker;
 
1524
        }
 
1525
 
 
1526
        while(  !open_list.empty()  ) {
 
1527
 
 
1528
                if (best_destination_weight <= open_list.front().aggregate_weight) {
 
1529
                        // best route to destination found already
 
1530
                        break;
 
1531
                }
 
1532
 
 
1533
                route_node_t current_node = open_list.pop();
 
1534
 
 
1535
                const uint16 current_halt_id = current_node.halt.get_id();
 
1536
                const uint16 current_weight = current_node.aggregate_weight;
 
1537
                halt_data_t & current_halt_data = halt_data[ current_halt_id ];
 
1538
 
 
1539
                // check if the current halt is already in closed list (or removed)
 
1540
                if(  !current_node.halt.is_bound()  ) {
 
1541
                        continue;
 
1542
                }
 
1543
                else if(  current_halt_data.best_weight < current_weight) {
 
1544
                        // shortest path to the current halt has already been found earlier
 
1545
                        // assert(markers[ current_halt_id ]==current_marker);
 
1546
                        continue;
 
1547
                }
 
1548
                else {
 
1549
                        // no need to update weight, as it is already the right one
 
1550
                        // assert(current_halt_data.best_weight == current_weight);
 
1551
                }
 
1552
 
 
1553
                if(  current_halt_data.destination  ) {
 
1554
                        // destination found
 
1555
                        ware.set_ziel( current_node.halt );
 
1556
                        ware.set_zwischenziel( current_halt_data.transfer );
 
1557
                        // update best_destination_weight to leave loop due to first check above
 
1558
                        best_destination_weight = current_weight;
 
1559
                        // if this destination halt is not a transfer halt -> do not proceed to process its reachable halt(s)
 
1560
                        if(  current_node.halt->serving_schedules[ware_catg_idx]<=1u  ) {
 
1561
                                continue;
 
1562
                        }
 
1563
                }
 
1564
 
 
1565
                if(  current_halt_data.depth > max_transfers  ) {
 
1566
                        // maximum transfer limit is reached -> do not add reachable halts to open list
 
1567
                        continue;
 
1568
                }
 
1569
 
 
1570
                const vector_tpl<connection_t> &conns = current_node.halt->connections[ware_catg_idx];
 
1571
                for(  uint32 i=0;  i<conns.get_count();  ++i  ) {
 
1572
 
 
1573
                        const connection_t &current_conn = conns[i];
 
1574
 
 
1575
                        const uint16 reachable_halt_id = current_conn.halt.get_id();
 
1576
 
 
1577
                        const uint16 total_weight = current_weight + current_conn.weight;
 
1578
 
 
1579
                        if(  !current_conn.halt.is_bound()  ) {
 
1580
                                // Case: halt removed -> make sure we never visit it again
 
1581
                                markers[ reachable_halt_id ] = current_marker;
 
1582
                                halt_data[ reachable_halt_id ].best_weight = 0;
 
1583
                        }
 
1584
                        else if(  markers[ reachable_halt_id ]!=current_marker  ) {
 
1585
                                // Case : not processed before and not destination
 
1586
 
 
1587
                                // indicate that this halt has been processed
 
1588
                                markers[ reachable_halt_id ] = current_marker;
 
1589
 
 
1590
                                // update data
 
1591
                                halt_data[ reachable_halt_id ].best_weight = total_weight;
 
1592
                                halt_data[ reachable_halt_id ].destination = false; // reset necessary if this was set by search_route
 
1593
                                halt_data[ reachable_halt_id ].depth       = current_halt_data.depth + 1u;
 
1594
                                halt_data[ reachable_halt_id ].transfer    = current_halt_data.transfer.get_id() ? current_halt_data.transfer : current_conn.halt;
 
1595
 
 
1596
                                if(  current_conn.halt->serving_schedules[ware_catg_idx]>1u  &&  allocation_pointer<max_hops  ) {
 
1597
                                        // Case : transfer halt
 
1598
                                        allocation_pointer++;
 
1599
                                        open_list.insert( route_node_t(current_conn.halt, total_weight) );
 
1600
                                }
 
1601
                        }       // if not processed before
 
1602
                        else {
 
1603
                                // Case : processed before (or destination halt)
 
1604
                                //        -> need to check whether we can reach it with smaller weight
 
1605
                                if(  total_weight<halt_data[ reachable_halt_id ].best_weight  ) {
 
1606
                                        // new weight is lower than lowest weight --> update halt data
 
1607
 
 
1608
                                        halt_data[ reachable_halt_id ].best_weight = total_weight;
 
1609
                                        halt_data[ reachable_halt_id ].transfer    = current_halt_data.transfer.get_id() ? current_halt_data.transfer : current_conn.halt;
 
1610
 
 
1611
                                        // for transfer/destination nodes create new node
 
1612
                                        if ( (halt_data[ reachable_halt_id ].destination  ||  current_conn.halt->serving_schedules[ware_catg_idx] > 1u)  &&  allocation_pointer<max_hops ) {
 
1613
                                                halt_data[ reachable_halt_id ].depth = current_halt_data.depth + 1u;
 
1614
                                                allocation_pointer++;
 
1615
                                                open_list.insert( route_node_t(current_conn.halt, total_weight) );
 
1616
                                        }
 
1617
                                }
 
1618
                        }       // else processed before
 
1619
                }       // for each connection entry
 
1620
        }
 
1621
 
 
1622
        // clear destinations since we may want to do another search with the same current_marker
 
1623
        for(uint32 i=0; i<dest_indices.get_count(); i++) {
 
1624
                halt_data[ dest_indices[i] ].destination = false;
 
1625
                if( halt_data[ dest_indices[i] ].best_weight == 65535u) {
 
1626
                        // not processed -> reset marker
 
1627
                        markers[ dest_indices[i] ] --;
 
1628
                }
 
1629
        }
 
1630
}
1381
1631
 
1382
1632
 
1383
1633
/**
1416
1666
 
1417
1667
 
1418
1668
 
1419
 
void haltestelle_t::liefere_an_fabrik(const ware_t& ware)
 
1669
void haltestelle_t::liefere_an_fabrik(const ware_t& ware) const
1420
1670
{
1421
 
        slist_iterator_tpl<fabrik_t *> fab_iter(fab_list);
1422
 
 
1423
 
        while(fab_iter.next()) {
1424
 
                fabrik_t * fab = fab_iter.get_current();
1425
 
 
1426
 
                const vector_tpl<ware_production_t>& eingang = fab->get_eingang();
1427
 
                for (uint32 i = 0; i < eingang.get_count(); i++) {
1428
 
                        if (eingang[i].get_typ() == ware.get_besch() && ware.get_zielpos() == fab->get_pos().get_2d()) {
1429
 
                                fab->liefere_an(ware.get_besch(), ware.menge);
1430
 
                                return;
1431
 
                        }
1432
 
                }
 
1671
        fabrik_t *const factory = fabrik_t::get_fab( welt, ware.get_zielpos() );
 
1672
        if(  factory  ) {
 
1673
                factory->liefere_an(ware.get_besch(), ware.menge);
1433
1674
        }
1434
1675
}
1435
1676
 
1475
1716
 
1476
1717
 
1477
1718
// will load something compatible with wtyp into the car which schedule is fpl
1478
 
ware_t haltestelle_t::hole_ab(const ware_besch_t *wtyp, uint32 maxi, const schedule_t *fpl, const spieler_t *sp )
 
1719
void haltestelle_t::hole_ab( slist_tpl<ware_t> &fracht, const ware_besch_t *wtyp, uint32 maxi, const schedule_t *fpl, const spieler_t *sp )
1479
1720
{
1480
1721
        // prissi: first iterate over the next stop, then over the ware
1481
1722
        // might be a little slower, but ensures that passengers to nearest stop are served first
1482
1723
        // this allows for separate high speed and normal service
1483
 
        const uint8 count = fpl->get_count();
1484
1724
        vector_tpl<ware_t> *warray = waren[wtyp->get_catg_index()];
1485
1725
 
1486
 
        if(warray!=NULL) {
1487
 
 
 
1726
        if (warray && !warray->empty()) {
1488
1727
                // da wir schon an der aktuellem haltestelle halten
1489
1728
                // startet die schleife ab 1, d.h. dem naechsten halt
 
1729
                const uint8 count = fpl->get_count();
1490
1730
                for(  uint8 i=1; i<count; i++  ) {
1491
1731
                        const uint8 wrap_i = (i + fpl->get_aktuell()) % count;
1492
1732
 
1495
1735
                                // we will come later here again ...
1496
1736
                                break;
1497
1737
                        }
1498
 
                        else if(  plan_halt.is_bound()  &&  warray->get_count()>0  ) {
 
1738
                        else if(  plan_halt.is_bound()  ) {
1499
1739
 
1500
1740
                                // The random offset will ensure that all goods have an equal chance to be loaded.
1501
1741
                                sint32 offset = simrand(warray->get_count());
1512
1752
                                                continue;
1513
1753
                                        }
1514
1754
 
 
1755
                                        // goods without route -> returning passengers/mail
 
1756
                                        if(  !tmp.get_zwischenziel().is_bound()  ) {
 
1757
                                                search_route_resumable(tmp);
 
1758
                                                if (!tmp.get_ziel().is_bound()) {
 
1759
                                                        // no route anymore
 
1760
                                                        tmp.menge = 0;
 
1761
                                                        continue;
 
1762
                                                }
 
1763
                                        }
 
1764
 
1515
1765
                                        // compatible car and right target stop?
1516
1766
                                        if(  tmp.get_zwischenziel()==plan_halt  ) {
1517
1767
 
1518
1768
                                                if(  plan_halt->is_overcrowded(wtyp->get_catg_index())  ) {
1519
 
                                                        if(  welt->get_einstellungen()->is_avoid_overcrowding()  &&  !(tmp.get_ziel()==plan_halt)  ) {
 
1769
                                                        if (welt->get_settings().is_avoid_overcrowding() && tmp.get_ziel() != plan_halt) {
1520
1770
                                                                // do not go for transfer to overcrowded transfer stop
1521
1771
                                                                continue;
1522
1772
                                                        }
1528
1778
                                                        // not all can be loaded
1529
1779
                                                        neu.menge = maxi;
1530
1780
                                                        tmp.menge -= maxi;
 
1781
                                                        maxi = 0;
1531
1782
                                                }
1532
1783
                                                else {
 
1784
                                                        maxi -= tmp.menge;
1533
1785
                                                        // leave an empty entry => joining will more often work
1534
1786
                                                        tmp.menge = 0;
1535
1787
                                                }
 
1788
                                                fracht.insert(neu);
 
1789
 
1536
1790
                                                book(neu.menge, HALT_DEPARTED);
1537
1791
                                                resort_freight_info = true;
1538
 
                                                return neu;
 
1792
 
 
1793
                                                if (maxi==0) {
 
1794
                                                        return;
 
1795
                                                }
1539
1796
                                        }
1540
1797
                                }
1541
1798
 
1543
1800
                        }
1544
1801
                }
1545
1802
        }
1546
 
 
1547
 
        // empty quantity of required type -> no effect
1548
 
        return ware_t (wtyp);
1549
1803
}
1550
1804
 
1551
1805
 
1581
1835
}
1582
1836
 
1583
1837
 
1584
 
 
1585
 
uint32 haltestelle_t::get_ware_fuer_zwischenziel(const ware_besch_t *wtyp, const halthandle_t zwischenziel) const
1586
 
{
1587
 
        uint32 sum = 0;
1588
 
        const vector_tpl<ware_t> * warray = waren[wtyp->get_catg_index()];
1589
 
        if(warray!=NULL) {
1590
 
                for(unsigned i=0;  i<warray->get_count();  i++ ) {
1591
 
                        const ware_t &ware = (*warray)[i];
1592
 
                        if(wtyp->get_index()==ware.get_index()  &&  ware.get_zwischenziel()==zwischenziel) {
1593
 
                                sum += ware.menge;
1594
 
                        }
1595
 
                }
1596
 
        }
1597
 
        return sum;
1598
 
}
1599
 
 
1600
 
 
1601
 
 
1602
1838
bool haltestelle_t::vereinige_waren(const ware_t &ware)
1603
1839
{
1604
1840
        // pruefen ob die ware mit bereits wartender ware vereinigt werden kann
1607
1843
                for(unsigned i=0;  i<warray->get_count();  i++ ) {
1608
1844
                        ware_t &tmp = (*warray)[i];
1609
1845
 
1610
 
                        // es wird auf basis von Haltestellen vereinigt
1611
 
                        // prissi: das ist aber ein Fehler f�r alle anderen G�ter, daher Zielkoordinaten f�r alles, was kein passagier ist ...
 
1846
                        // join packets with same destination
1612
1847
                        if(ware.same_destination(tmp)) {
1613
1848
                                if(  ware.get_zwischenziel().is_bound()  &&  ware.get_zwischenziel()!=self  ) {
1614
1849
                                        // update route if there is newer route
1658
1893
uint32 haltestelle_t::starte_mit_route(ware_t ware)
1659
1894
{
1660
1895
        if(ware.get_ziel()==self) {
1661
 
                if(ware.is_freight()) {
 
1896
                if(  ware.to_factory  ) {
1662
1897
                        // muss an fabrik geliefert werden
1663
1898
                        liefere_an_fabrik(ware);
1664
1899
                }
1669
1904
        // no valid next stops? Or we are the next stop?
1670
1905
        if(ware.get_zwischenziel()==self) {
1671
1906
                dbg->error("haltestelle_t::starte_mit_route()","route cannot contain us as first transfer stop => recalc route!");
1672
 
                if(  suche_route( ware, NULL, false )==NO_ROUTE  ) {
 
1907
                if(  search_route( &self, 1u, false, ware )==NO_ROUTE  ) {
1673
1908
                        // no route found?
1674
1909
                        dbg->error("haltestelle_t::starte_mit_route()","no route found!");
1675
1910
                        return ware.menge;
1705
1940
 
1706
1941
        // did we arrived?
1707
1942
        if(welt->lookup(ware.get_zielpos())->is_connected(self)) {
1708
 
                if(ware.is_freight()) {
 
1943
                if(  ware.to_factory  ) {
1709
1944
                        // muss an fabrik geliefert werden
1710
1945
                        liefere_an_fabrik(ware);
1711
1946
                }
1712
1947
                else if(ware.get_besch()==warenbauer_t::passagiere) {
1713
1948
                        // arriving passenger may create pedestrians
1714
 
                        if(welt->get_einstellungen()->get_show_pax()) {
 
1949
                        if (welt->get_settings().get_show_pax()) {
1715
1950
                                int menge = ware.menge;
1716
1951
                                for (slist_tpl<tile_t>::const_iterator i = tiles.begin(), end = tiles.end(); menge > 0 && i != end; ++i) {
1717
1952
                                        grund_t* gr = i->grund;
1729
1964
        }
1730
1965
 
1731
1966
        // not near enough => we need to do a rerouting
1732
 
        if(  suche_route( ware, NULL, false )==NO_ROUTE  ) {
 
1967
        search_route_resumable(ware);
 
1968
        if (!ware.get_ziel().is_bound()) {
1733
1969
                // target no longer there => delete
1734
1970
 
1735
1971
                INT_CHECK("simhalt 1364");
1805
2041
                for(unsigned i=0; i<warenbauer_t::get_max_catg_index(); i++) {
1806
2042
                        const vector_tpl<ware_t> * warray = waren[i];
1807
2043
                        if(warray) {
1808
 
                                freight_list_sorter_t::sort_freight(warray, buf, (freight_list_sorter_t::sort_mode_t)sortierung, NULL, "waiting");
 
2044
                                freight_list_sorter_t::sort_freight(warray, buf, (freight_list_sorter_t::sort_mode_t)sortierung, NULL, "waiting", welt);
1809
2045
                        }
1810
2046
                }
1811
2047
        }
1813
2049
 
1814
2050
 
1815
2051
 
1816
 
void haltestelle_t::get_short_freight_info(cbuffer_t & buf)
 
2052
void haltestelle_t::get_short_freight_info(cbuffer_t & buf) const
1817
2053
{
1818
2054
        bool got_one = false;
1819
2055
 
1829
2065
                                        buf.append(", ");
1830
2066
                                }
1831
2067
 
1832
 
                                buf.append(summe);
1833
 
                                buf.append(translator::translate(wtyp->get_mass()));
1834
 
                                buf.append(" ");
1835
 
                                buf.append(translator::translate(wtyp->get_name()));
 
2068
                                buf.printf("%d%s %s", summe, translator::translate(wtyp->get_mass()), translator::translate(wtyp->get_name()));
1836
2069
 
1837
2070
                                got_one = true;
1838
2071
                        }
1858
2091
}
1859
2092
 
1860
2093
 
1861
 
 
1862
 
// changes this to a publix transfer exchange stop
1863
 
sint64 haltestelle_t::calc_maintenance()
 
2094
sint64 haltestelle_t::calc_maintenance() const
1864
2095
{
1865
2096
        sint64 maintenance = 0;
1866
2097
        for(slist_tpl<tile_t>::const_iterator i = tiles.begin(), end = tiles.end(); i != end; ++i) {
1867
2098
                grund_t* gr = i->grund;
1868
2099
                gebaeude_t* gb = gr->find<gebaeude_t>();
1869
2100
                if(gb) {
1870
 
                        maintenance += welt->get_einstellungen()->maint_building*gb->get_tile()->get_besch()->get_level();
 
2101
                        maintenance += welt->get_settings().maint_building * gb->get_tile()->get_besch()->get_level();
1871
2102
                }
1872
2103
        }
1873
2104
        return maintenance;
1890
2121
                        gebaeude_t* gb = gr->find<gebaeude_t>();
1891
2122
                        if(gb) {
1892
2123
                                spieler_t *gb_sp=gb->get_besitzer();
1893
 
                                sint64 costs = welt->get_einstellungen()->maint_building*gb->get_tile()->get_besch()->get_level();
 
2124
                                sint64 const costs = welt->get_settings().maint_building * gb->get_tile()->get_besch()->get_level();
1894
2125
                                total_costs += costs;
1895
2126
                                spieler_t::add_maintenance( gb_sp, -costs );
1896
2127
                                gb->set_besitzer(public_owner);
1909
2140
                        }
1910
2141
                }
1911
2142
                // transfer ownership
1912
 
                spieler_t::accounting( sp, -((total_costs*60)<<(welt->ticks_per_world_month_shift-18)), get_basis_pos(), COST_CONSTRUCTION);
 
2143
                spieler_t::accounting( sp, -total_costs*60, get_basis_pos(), COST_CONSTRUCTION);
1913
2144
                besitzer_p->halt_remove(self);
1914
2145
                besitzer_p = public_owner;
1915
2146
                public_owner->halt_add(self);
1943
2174
                                spieler_t *gb_sp=gb->get_besitzer();
1944
2175
                                if(public_owner!=gb_sp) {
1945
2176
                                        spieler_t *gb_sp=gb->get_besitzer();
1946
 
                                        sint64 costs = welt->get_einstellungen()->maint_building*gb->get_tile()->get_besch()->get_level();
 
2177
                                        sint64 const costs = welt->get_settings().maint_building * gb->get_tile()->get_besch()->get_level();
1947
2178
                                        spieler_t::add_maintenance( gb_sp, -costs );
1948
 
                                        spieler_t::accounting(gb_sp, -((costs*60)<<(welt->ticks_per_world_month_shift-18)), gr->get_pos().get_2d(), COST_CONSTRUCTION);
 
2179
                                        spieler_t::accounting(gb_sp, costs*60, gr->get_pos().get_2d(), COST_CONSTRUCTION);
1949
2180
                                        gb->set_besitzer(public_owner);
1950
2181
                                        gb->set_flag(ding_t::dirty);
1951
2182
                                        spieler_t::add_maintenance(public_owner, costs );
1966
2197
 
1967
2198
        // tell the world of it ...
1968
2199
        if(  sp->get_player_nr()!=1  &&  umgebung_t::networkmode  ) {
1969
 
                cbuffer_t buf(256);
 
2200
                cbuffer_t buf;
1970
2201
                buf.printf( translator::translate("%s at (%i,%i) now public stop."), get_name(), get_basis_pos().x, get_basis_pos().y );
1971
2202
                welt->get_message()->add_message( buf, get_basis_pos(), message_t::ai, PLAYER_FLAG|sp->get_player_nr(), IMG_LEER );
1972
2203
        }
2002
2233
 */
2003
2234
void haltestelle_t::recalc_station_type()
2004
2235
{
2005
 
        int new_station_type = 0;
 
2236
        stationtyp new_station_type = invalid;
2006
2237
        capacity[0] = 0;
2007
2238
        capacity[1] = 0;
2008
2239
        capacity[2] = 0;
2021
2252
                        if(besch) {
2022
2253
                                // enabled the matching types
2023
2254
                                enables |= besch->get_enabled();
2024
 
                                if(  welt->get_einstellungen()->is_seperate_halt_capacities()  ) {
 
2255
                                if (welt->get_settings().is_seperate_halt_capacities()) {
2025
2256
                                        if(besch->get_enabled()&1) {
2026
2257
                                                capacity[0] += besch->get_level()*32;
2027
2258
                                        }
2094
2325
 
2095
2326
                // enabled the matching types
2096
2327
                enables |= besch->get_enabled();
2097
 
                if(  welt->get_einstellungen()->is_seperate_halt_capacities()  ) {
 
2328
                if (welt->get_settings().is_seperate_halt_capacities()) {
2098
2329
                        if(besch->get_enabled()&1) {
2099
2330
                                capacity[0] += besch->get_level()*32;
2100
2331
                        }
2111
2342
                        capacity[2] = capacity[1] = capacity[0];
2112
2343
                }
2113
2344
        }
2114
 
        station_type = (haltestelle_t::stationtyp)new_station_type;
 
2345
        station_type = new_station_type;
2115
2346
        recalc_status();
2116
2347
 
2117
2348
//DBG_DEBUG("haltestelle_t::recalc_station_type()","result=%x, capacity[0]=%i, capacity[1], capacity[2]",new_station_type,capacity[0],capacity[1],capacity[2]);
2137
2368
        sint32 spieler_n;
2138
2369
        koord3d k;
2139
2370
 
 
2371
        // will restore halthandle_t after loading
 
2372
        if(file->get_version() > 110005) {
 
2373
                if(file->is_saving()) {
 
2374
                        uint16 halt_id = self.is_bound() ? self.get_id() : 0;
 
2375
                        file->rdwr_short(halt_id);
 
2376
                }
 
2377
                else {
 
2378
                        uint16 halt_id;
 
2379
                        file->rdwr_short(halt_id);
 
2380
                        self.set_id(halt_id);
 
2381
                        self = halthandle_t(this, halt_id);
 
2382
                }
 
2383
        }
 
2384
        else {
 
2385
                if (file->is_loading()) {
 
2386
                        self = halthandle_t(this);
 
2387
                }
 
2388
        }
 
2389
 
2140
2390
        if(file->is_saving()) {
2141
2391
                spieler_n = welt->sp2num( besitzer_p );
2142
2392
        }
2156
2406
        if(file->is_loading()) {
2157
2407
                besitzer_p = welt->get_spieler(spieler_n);
2158
2408
                k.rdwr( file );
2159
 
                slist_tpl <grund_t *>grund_list;
2160
2409
                while(k!=koord3d::invalid) {
2161
2410
                        grund_t *gr = welt->lookup(k);
2162
2411
                        if(!gr) {
2235
2484
                // however, we have to rebuilt them anyway for the new format
2236
2485
                if(file->get_version()<99013) {
2237
2486
                        file->rdwr_short(count);
 
2487
                        warenziel_t dummy;
2238
2488
                        for(int i=0; i<count; i++) {
2239
 
                                warenziel_t wz (file);
 
2489
                                dummy.rdwr(file);
2240
2490
                        }
2241
2491
                }
2242
2492
 
2472
2722
 
2473
2723
        // appends this to the ground
2474
2724
        // after that, the surrounding ground will know of this station
2475
 
        int cov = welt->get_einstellungen()->get_station_coverage();
 
2725
        int const cov = welt->get_settings().get_station_coverage();
2476
2726
        for (int y = -cov; y <= cov; y++) {
2477
2727
                for (int x = -cov; x <= cov; x++) {
2478
2728
                        koord p=pos+koord(x,y);
2630
2880
                pl->get_kartenboden()->set_flag(grund_t::dirty);
2631
2881
        }
2632
2882
 
2633
 
        int cov = welt->get_einstellungen()->get_station_coverage();
 
2883
        int const cov = welt->get_settings().get_station_coverage();
2634
2884
        for (int y = -cov; y <= cov; y++) {
2635
2885
                for (int x = -cov; x <= cov; x++) {
2636
2886
                        planquadrat_t *pl = welt->access( gr->get_pos().get_2d()+koord(x,y) );
2681
2931
 
2682
2932
 
2683
2933
 
2684
 
bool haltestelle_t::existiert_in_welt()
 
2934
bool haltestelle_t::existiert_in_welt() const
2685
2935
{
2686
2936
        return !tiles.empty();
2687
2937
}
2718
2968
void haltestelle_t::mark_unmark_coverage(const bool mark) const
2719
2969
{
2720
2970
        // iterate over all tiles
 
2971
        uint16 const cov = welt->get_settings().get_station_coverage();
 
2972
        koord  const size(cov * 2 + 1, cov * 2 + 1);
2721
2973
        for (slist_tpl<tile_t>::const_iterator i = tiles.begin(), end = tiles.end(); i != end; ++i) {
2722
 
                koord size( welt->get_einstellungen()->get_station_coverage()*2+1, welt->get_einstellungen()->get_station_coverage()*2+1);
2723
2974
                welt->mark_area( i->grund->get_pos()-size/2, size, mark );
2724
2975
        }
2725
2976
}
2764
3015
}
2765
3016
 
2766
3017
 
2767
 
 
2768
3018
/* reserves a position (caution: railblocks work differently!
2769
3019
 * @author prissi
2770
3020
 */
2796
3046
}
2797
3047
 
2798
3048
 
2799
 
 
2800
3049
/* frees a reserved  position (caution: railblocks work differently!
2801
3050
 * @author prissi
2802
3051
 */
2814
3063
}
2815
3064
 
2816
3065
 
2817
 
 
2818
3066
/* can a convoi reserve this position?
2819
3067
 * @author prissi
2820
3068
 */
2842
3090
        return false;
2843
3091
}
2844
3092
 
 
3093
 
2845
3094
/* deletes factory references so map rotation won't segfault
2846
3095
*/
2847
3096
void haltestelle_t::release_factory_links()