1 /*
2 * Copyright (c) 2008 Markus Pristovsek
3 *
4 * This file is part of the Simutrans project under the artistic licence.
5 * (see licence.txt)
6 */
7
8 /* simple passenger AI (not using trains, not pre-optimized network) */
9
10 #include "../simcity.h"
11 #include "../simconvoi.h"
12 #include "../simfab.h"
13 #include "../simhalt.h"
14 #include "../simline.h"
15 #include "../simmenu.h"
16 #include "../simmesg.h"
17 #include "../simworld.h"
18
19 #include "../bauer/brueckenbauer.h"
20 #include "../bauer/hausbauer.h"
21 #include "../bauer/tunnelbauer.h"
22 #include "../bauer/vehikelbauer.h"
23 #include "../bauer/wegbauer.h"
24
25 #include "../dataobj/schedule.h"
26 #include "../dataobj/loadsave.h"
27 #include "../dataobj/marker.h"
28
29 #include "../utils/cbuffer_t.h"
30 #include "../utils/simrandom.h"
31 #include "../utils/simstring.h"
32
33 #include "../vehicle/simvehicle.h"
34
35 #include "ai_passenger.h"
36 #include "finance.h"
37
38
ai_passenger_t(uint8 nr)39 ai_passenger_t::ai_passenger_t(uint8 nr) : ai_t( nr )
40 {
41 state = NR_INIT;
42
43 road_vehicle = NULL;
44 road_weg = NULL;
45
46 next_construction_steps = welt->get_steps() + 50;
47
48 road_transport = true;
49 rail_transport = false;
50 air_transport = true;
51 ship_transport = true;
52
53 start_stadt = end_stadt = NULL;
54 ziel = NULL;
55 end_attraction = NULL;
56 }
57
58
59 /* Activates/deactivates a player
60 * @author prissi
61 */
set_active(bool new_state)62 bool ai_passenger_t::set_active(bool new_state)
63 {
64 // only activate, when there are buses available!
65 if( new_state ) {
66 new_state = NULL!=vehikel_search( road_wt, 50, 80, goods_manager_t::passengers, false);
67 }
68 return player_t::set_active( new_state );
69 }
70
71
72 /* return the hub of a city (always the very first stop) or zero
73 * @author prissi
74 */
get_our_hub(const stadt_t * s) const75 halthandle_t ai_passenger_t::get_our_hub( const stadt_t *s ) const
76 {
77 FOR(vector_tpl<halthandle_t>, const halt, haltestelle_t::get_alle_haltestellen()) {
78 if (halt->get_owner() == sim::up_cast<player_t const*>(this)) {
79 if( halt->get_pax_enabled() && (halt->get_station_type()&haltestelle_t::busstop)!=0 ) {
80 koord h=halt->get_basis_pos();
81 if(h.x>=s->get_linksoben().x && h.y>=s->get_linksoben().y && h.x<=s->get_rechtsunten().x && h.y<=s->get_rechtsunten().y ) {
82 return halt;
83 }
84 }
85 }
86 }
87 return halthandle_t();
88 }
89
90
find_area_for_hub(const koord lo,const koord ru,const koord basis) const91 koord ai_passenger_t::find_area_for_hub( const koord lo, const koord ru, const koord basis ) const
92 {
93 // no found found
94 koord best_pos = koord::invalid;
95 // "shortest" distance
96 int dist = 999;
97
98 for( sint16 x=lo.x; x<=ru.x; x++ ) {
99 for( sint16 y=lo.y; y<=ru.y; y++ ) {
100 const koord trypos(x,y);
101 const grund_t * gr = welt->lookup_kartenboden(trypos);
102 if(gr) {
103 // flat, solid
104 if( gr->get_typ()==grund_t::boden && gr->get_grund_hang()==slope_t::flat ) {
105 const obj_t* obj = gr->obj_bei(0);
106 int test_dist = koord_distance( trypos, basis );
107 if (!obj || !obj->get_owner() || obj->get_owner() == sim::up_cast<player_t const*>(this)) {
108 if( gr->is_halt() && check_owner( gr->get_halt()->get_owner(), this ) && gr->hat_weg(road_wt) ) {
109 // ok, one halt belongs already to us ... (should not really happen!) but might be a public stop
110 return trypos;
111 } else if( test_dist<dist && gr->hat_weg(road_wt) && !gr->is_halt() ) {
112 ribi_t::ribi ribi = gr->get_weg_ribi_unmasked(road_wt);
113 if( ribi_t::is_straight(ribi) || ribi_t::is_single(ribi) ) {
114 best_pos = trypos;
115 dist = test_dist;
116 }
117 } else if( test_dist+2<dist && gr->ist_natur() ) {
118 // also ok for a stop, but second choice
119 // so we gave it a malus of 2
120 best_pos = trypos;
121 dist = test_dist+2;
122 }
123 }
124 }
125 }
126 }
127 }
128 DBG_MESSAGE("ai_passenger_t::find_area_for_hub()","suggest hub at (%i,%i)",best_pos.x,best_pos.y);
129 return best_pos;
130 }
131
132
133 /* tries to built a hub near the koordinate
134 * @author prissi
135 */
find_place_for_hub(const stadt_t * s) const136 koord ai_passenger_t::find_place_for_hub( const stadt_t *s ) const
137 {
138 halthandle_t h = get_our_hub( s );
139 if(h.is_bound()) {
140 return h->get_basis_pos();
141 }
142 return find_area_for_hub( s->get_linksoben(), s->get_rechtsunten(), s->get_pos() );
143 }
144
145
find_harbour_pos(karte_t * welt,const stadt_t * s)146 koord ai_passenger_t::find_harbour_pos(karte_t* welt, const stadt_t *s )
147 {
148 koord bestpos = koord::invalid, k;
149 sint32 bestdist = 999999;
150
151 // try to find an airport place as close to the city as possible
152 for( k.y=max(6,s->get_linksoben().y-10); k.y<=min(welt->get_size().y-3-6,s->get_rechtsunten().y+10); k.y++ ) {
153 for( k.x=max(6,s->get_linksoben().x-25); k.x<=min(welt->get_size().x-3-6,s->get_rechtsunten().x+10); k.x++ ) {
154 sint32 testdist = koord_distance( k, s->get_pos() );
155 if( testdist<bestdist ) {
156 if( k.x+2<s->get_linksoben().x || k.y+2<s->get_linksoben().y || k.x>=s->get_rechtsunten().x || k.y>=s->get_rechtsunten().y ) {
157 // malus for out of town
158 testdist += 5;
159 }
160 if( testdist<bestdist ) {
161 grund_t *gr = welt->lookup_kartenboden(k);
162 slope_t::type hang = gr->get_grund_hang();
163 if( gr->ist_natur() && gr->get_hoehe() == welt->get_water_hgt(k) && slope_t::is_way(hang) && welt->is_water( k - koord(hang), koord(hang) * 4 + koord(1, 1) ) ) {
164 // can built busstop here?
165 koord bushalt = k+koord(hang);
166 gr = welt->lookup_kartenboden(bushalt);
167 if(gr && gr->ist_natur()) {
168 bestpos = k;
169 bestdist = testdist;
170 }
171 }
172 }
173 }
174 }
175 }
176 return bestpos;
177 }
178
179
create_water_transport_vehikel(const stadt_t * start_stadt,const koord target_pos)180 bool ai_passenger_t::create_water_transport_vehikel(const stadt_t* start_stadt, const koord target_pos)
181 {
182 const vehicle_desc_t *v_desc = vehikel_search(water_wt, 10, 40, goods_manager_t::passengers, false);
183 if(v_desc==NULL ) {
184 // no ship there
185 return false;
186 }
187
188 if( convoihandle_t::is_exhausted() ) {
189 // too many convois => cannot do anything about this ...
190 return false;
191 }
192
193 stadt_t *end_stadt = NULL;
194 grund_t *ziel = welt->lookup_kartenboden(target_pos);
195 gebaeude_t *gb = ziel->find<gebaeude_t>();
196 if(gb && gb->is_townhall()) {
197 end_stadt = gb->get_stadt();
198 }
199 else if(!ziel->is_halt() || !ziel->is_water()) {
200 // not townhall, not factory => we will not built this line for attractions!
201 return false;
202 }
203
204 halthandle_t start_hub = get_our_hub( start_stadt );
205 halthandle_t start_connect_hub;
206 koord start_harbour = koord::invalid;
207 if(start_hub.is_bound()) {
208 if( (start_hub->get_station_type()&haltestelle_t::dock)==0 ) {
209 start_connect_hub = start_hub;
210 start_hub = halthandle_t();
211 // is there already one harbour next to this one?
212 FOR(vector_tpl<haltestelle_t::connection_t>, const& i, start_connect_hub->get_pax_connections()) {
213 halthandle_t const h = i.halt;
214 if( h->get_station_type()&haltestelle_t::dock ) {
215 start_hub = h;
216 break;
217 }
218 }
219 }
220 else {
221 start_harbour = start_hub->get_basis_pos();
222 }
223 }
224 // find an dock place
225 if(!start_hub.is_bound()) {
226 start_harbour = find_harbour_pos( welt, start_stadt );
227 }
228 if(start_harbour==koord::invalid) {
229 // sorry, no suitable place
230 return false;
231 }
232 // same for end
233 halthandle_t end_hub = end_stadt ? get_our_hub( end_stadt ) : ziel->get_halt();
234 halthandle_t end_connect_hub;
235 koord end_harbour = koord::invalid;
236 if(end_hub.is_bound()) {
237 if( (end_hub->get_station_type()&haltestelle_t::dock)==0 ) {
238 end_connect_hub = end_hub;
239 end_hub = halthandle_t();
240 // is there already one harbour next to this one?
241 FOR(vector_tpl<haltestelle_t::connection_t>, const& i, end_connect_hub->get_pax_connections()) {
242 halthandle_t const h = i.halt;
243 if( h->get_station_type()&haltestelle_t::dock ) {
244 start_hub = h;
245 break;
246 }
247 }
248 }
249 else {
250 end_harbour = end_hub->get_basis_pos();
251 }
252 }
253 if(!end_hub.is_bound() && end_stadt) {
254 // find an dock place
255 end_harbour = find_harbour_pos( welt, end_stadt );
256 }
257 if(end_harbour==koord::invalid) {
258 // sorry, no suitable place
259 return false;
260 }
261
262 const koord start_dx(welt->lookup_kartenboden(start_harbour)->get_grund_hang());
263 const koord end_dx(welt->lookup_kartenboden(end_harbour)->get_grund_hang());
264
265 // now we must check, if these two seas are connected
266 {
267 // we use the free own vehicle_desc_t
268 vehicle_desc_t remover_desc( water_wt, 500, vehicle_desc_t::diesel );
269 vehicle_t* test_driver = vehicle_builder_t::build( koord3d( start_harbour - start_dx, welt->get_water_hgt( start_harbour - start_dx ) ), this, NULL, &remover_desc );
270 test_driver->set_flag( obj_t::not_on_map );
271 route_t verbindung;
272 bool connected = verbindung.calc_route( welt, koord3d( start_harbour - start_dx, welt->get_water_hgt( start_harbour - start_dx ) ), koord3d( end_harbour - end_dx, welt->get_water_hgt( end_harbour - end_dx ) ), test_driver, 0, 0 );
273 delete test_driver;
274 if(!connected) {
275 return false;
276 }
277 }
278
279 // build the harbour if necessary
280 if(!start_hub.is_bound()) {
281 koord bushalt = start_harbour+start_dx;
282 const koord town_road = find_place_for_hub( start_stadt );
283 // first: built street to harbour
284 if(town_road!=bushalt) {
285 way_builder_t bauigel(this);
286 // no bridges => otherwise first tile might be bridge start ...
287 bauigel.init_builder( way_builder_t::strasse, way_builder_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), type_flat ), tunnel_builder_t::get_tunnel_desc(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()), NULL );
288 bauigel.set_keep_existing_faster_ways(true);
289 bauigel.set_keep_city_roads(true);
290 bauigel.set_maximum(10000);
291 bauigel.calc_route( welt->lookup_kartenboden(bushalt)->get_pos(), welt->lookup_kartenboden(town_road)->get_pos() );
292 if(bauigel.get_count()-1 <= 1) {
293 return false;
294 }
295 bauigel.build();
296 }
297 }
298 if(!end_hub.is_bound()) {
299 koord bushalt = end_harbour+end_dx;
300 const koord town_road = find_place_for_hub( end_stadt );
301 // first: built street to harbour
302 if(town_road!=bushalt) {
303 way_builder_t bauigel(this);
304 // no bridges => otherwise first tile might be bridge start ...
305 bauigel.init_builder( way_builder_t::strasse, way_builder_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), type_flat ), tunnel_builder_t::get_tunnel_desc(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()), NULL );
306 bauigel.set_keep_existing_faster_ways(true);
307 bauigel.set_keep_city_roads(true);
308 bauigel.set_maximum(10000);
309 bauigel.calc_route( welt->lookup_kartenboden(bushalt)->get_pos(), welt->lookup_kartenboden(town_road)->get_pos() );
310 if(bauigel.get_count()-1 <= 1) {
311 return false;
312 }
313 bauigel.build();
314 }
315 }
316 // now built the stops ... (since the roads were ok!)
317 if(!start_hub.is_bound()) {
318 /* first we must built the bus stop, since this will be the default stop for all our buses
319 * we want to keep the name of a dock, thus we will create it beforehand
320 */
321 koord bushalt = start_harbour+start_dx;
322 const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX );
323 // now built the bus stop
324 if(!call_general_tool( TOOL_BUILD_STATION, bushalt, busstop_desc->get_name() )) {
325 return false;
326 }
327 // and change name to dock ...
328 grund_t *gr = welt->lookup_kartenboden(bushalt);
329 halthandle_t halt = gr ? gr->get_halt() : halthandle_t();
330 if (halt.is_bound()) { // it should be, but avoid crashes
331 char* const name = halt->create_name(bushalt, "Dock");
332 halt->set_name( name );
333 free(name);
334 }
335 // finally built the dock
336 const building_desc_t* dock_desc = hausbauer_t::get_random_station(building_desc_t::dock, water_wt, welt->get_timeline_year_month(), 0);
337 welt->lookup_kartenboden(start_harbour)->obj_loesche_alle(this);
338 call_general_tool( TOOL_BUILD_STATION, start_harbour, dock_desc->get_name() );
339 grund_t *harbour_gr = welt->lookup_kartenboden(start_harbour);
340 start_hub = harbour_gr ? harbour_gr->get_halt() : halthandle_t();
341 // eventually we must built a hub in the next town
342 start_connect_hub = get_our_hub( start_stadt );
343 if(!start_connect_hub.is_bound()) {
344 koord sch = find_place_for_hub( start_stadt );
345 call_general_tool( TOOL_BUILD_STATION, sch, busstop_desc->get_name() );
346 start_connect_hub = get_our_hub( start_stadt );
347 assert( start_connect_hub.is_bound() );
348 }
349 }
350 if(!end_hub.is_bound()) {
351 /* again we must built the bus stop first, since this will be the default stop for all our buses
352 * we want to keep the name of a dock, thus we will create it beforehand
353 */
354 koord bushalt = end_harbour+end_dx;
355 const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX );
356 // now built the bus stop
357 if(!call_general_tool( TOOL_BUILD_STATION, bushalt, busstop_desc->get_name() )) {
358 return false;
359 }
360 // and change name to dock ...
361 grund_t *gr = welt->lookup_kartenboden(bushalt);
362 halthandle_t halt = gr ? gr->get_halt() : halthandle_t();
363 if (halt.is_bound()) { // it should be, but avoid crashes
364 char* const name = halt->create_name(bushalt, "Dock");
365 halt->set_name( name );
366 free(name);
367 }
368 // finally built the dock
369 const building_desc_t* dock_desc = hausbauer_t::get_random_station(building_desc_t::dock, water_wt, welt->get_timeline_year_month(), 0 );
370 welt->lookup_kartenboden(end_harbour)->obj_loesche_alle(this);
371 call_general_tool( TOOL_BUILD_STATION, end_harbour, dock_desc->get_name() );
372 grund_t *harbour_gr = welt->lookup_kartenboden(end_harbour);
373 end_hub = harbour_gr ? harbour_gr->get_halt() : halthandle_t();
374 // eventually we must built a hub in the next town
375 end_connect_hub = get_our_hub( end_stadt );
376 if(!end_connect_hub.is_bound()) {
377 koord ech = find_place_for_hub( end_stadt );
378 call_general_tool( TOOL_BUILD_STATION, ech, busstop_desc->get_name() );
379 end_connect_hub = get_our_hub( end_stadt );
380 assert( end_connect_hub.is_bound() );
381 }
382 }
383
384 uint16 const cov = welt->get_settings().get_station_coverage();
385 // now we have harbour => find start position for ships
386 koord pos1 = start_harbour-start_dx;
387 koord start_pos = pos1;
388 for (int y = pos1.y - cov; y <= pos1.y + cov; ++y) {
389 for (int x = pos1.x - cov; x <= pos1.x + cov; ++x) {
390 koord p(x,y);
391 const planquadrat_t *plan = welt->access(p);
392 if(plan) {
393 grund_t *gr = plan->get_kartenboden();
394 if( gr->is_water() && !gr->get_halt().is_bound() ) {
395 if(plan->get_haltlist_count()>=1 && plan->get_haltlist()[0]==start_hub && koord_distance(start_pos,end_harbour)>koord_distance(p,end_harbour)) {
396 start_pos = p;
397 }
398 }
399 }
400 }
401 }
402 // now we have harbour => find start position for ships
403 pos1 = end_harbour-end_dx;
404 koord end_pos = pos1;
405 for (int y = pos1.y - cov; y <= pos1.y + cov; ++y) {
406 for (int x = pos1.x - cov; x <= pos1.x + cov; ++x) {
407 koord p(x,y);
408 const planquadrat_t *plan = welt->access(p);
409 if(plan) {
410 grund_t *gr = plan->get_kartenboden();
411 if( gr->is_water() && !gr->get_halt().is_bound() ) {
412 if(plan->get_haltlist_count()>=1 && plan->get_haltlist()[0]==end_hub && koord_distance(end_pos,start_harbour)>koord_distance(p,start_harbour)) {
413 end_pos = p;
414 }
415 }
416 }
417 }
418 }
419
420 // since 86.01 we use lines for vehicles ...
421 schedule_t *schedule=new ship_schedule_t();
422 schedule->append( welt->lookup_kartenboden(start_pos), 0, 0 );
423 schedule->append( welt->lookup_kartenboden(end_pos), 90, 0 );
424 schedule->set_current_stop( 1 );
425 schedule->finish_editing();
426 linehandle_t line=simlinemgmt.create_line(simline_t::shipline,this,schedule);
427 delete schedule;
428
429 // now create one ship
430 vehicle_t* v = vehicle_builder_t::build( koord3d( start_pos, welt->get_water_hgt( start_pos ) ), this, NULL, v_desc );
431 convoi_t* cnv = new convoi_t(this);
432 cnv->set_name(v->get_desc()->get_name());
433 cnv->add_vehikel( v );
434 cnv->set_line(line);
435 cnv->start();
436
437 // eventually build a shuttle bus ...
438 if(start_connect_hub.is_bound() && start_connect_hub!=start_hub) {
439 koord stops[2] = { start_harbour+start_dx, start_connect_hub->get_basis_pos() };
440 create_bus_transport_vehikel( stops[1], 1, stops, 2, false );
441 }
442
443 // eventually build a airport shuttle bus ...
444 if(end_connect_hub.is_bound() && end_connect_hub!=end_hub) {
445 koord stops[2] = { end_harbour+end_dx, end_connect_hub->get_basis_pos() };
446 create_bus_transport_vehikel( stops[1], 1, stops, 2, false );
447 }
448
449 return true;
450 }
451
452
build_airport(const stadt_t * city,koord pos,int rotation)453 halthandle_t ai_passenger_t::build_airport(const stadt_t* city, koord pos, int rotation)
454 {
455 // not too close to border?
456 if(pos.x<6 || pos.y<6 || pos.x+3+6>=welt->get_size().x || pos.y+3+6>=welt->get_size().y ) {
457 return halthandle_t();
458 }
459 // ok, not prematurely doomed
460 // can we built airports at all?
461 const way_desc_t *taxi_desc = way_builder_t::weg_search( air_wt, 25, welt->get_timeline_year_month(), type_flat );
462 const way_desc_t *runway_desc = way_builder_t::weg_search( air_wt, 250, welt->get_timeline_year_month(), type_runway );
463 if(taxi_desc==NULL || runway_desc==NULL) {
464 return halthandle_t();
465 }
466 // first, check if at least one tile is within city limits
467 const koord lo = city->get_linksoben();
468 koord size(3-1,3-1);
469 // make sure pos is within city limits!
470 if(pos.x<lo.x) {
471 pos.x += size.x;
472 size.x = -size.x;
473 }
474 if(pos.y<lo.y) {
475 pos.y += size.y;
476 size.y = -size.y;
477 }
478 // find coord to connect in the town
479 halthandle_t hub = get_our_hub( city );
480 const koord town_road = hub.is_bound() ? hub->get_basis_pos() : find_place_for_hub( city );
481 if( town_road==koord::invalid) {
482 return halthandle_t();
483 }
484 // ok, now we could built it => flatten the land
485 sint8 h = max( welt->get_water_hgt(pos) + 1, welt->lookup_kartenboden(pos)->get_hoehe() );
486 const koord dx( size.x/2, size.y/2 );
487 for( sint16 i=0; i!=size.y+dx.y; i+=dx.y ) {
488 for( sint16 j=0; j!=size.x+dx.x; j+=dx.x ) {
489 climate c = welt->get_climate(pos+koord(j,i));
490 if(!welt->flatten_tile(this,pos+koord(j,i),h)) {
491 return halthandle_t();
492 }
493 // ensure is land
494 grund_t* bd = welt->lookup_kartenboden(pos+koord(j,i));
495 if (bd->get_typ() == grund_t::wasser) {
496 welt->set_water_hgt(pos+koord(j,i), bd->get_hoehe()-1);
497 welt->access(pos+koord(j,i))->correct_water();
498 welt->set_climate(pos+koord(j,i), c, true);
499 }
500 }
501 }
502 // now taxiways
503 way_builder_t bauigel(this);
504 // 3x3 layout, first we make the taxiway cross
505 koord center=pos+dx;
506 bauigel.init_builder( way_builder_t::luft, taxi_desc, NULL, NULL );
507 bauigel.calc_straight_route( welt->lookup_kartenboden(center+koord::north)->get_pos(), welt->lookup_kartenboden(center+koord::south)->get_pos() );
508 assert(bauigel.get_count()-1 > 1);
509 bauigel.build();
510 bauigel.init_builder( way_builder_t::luft, taxi_desc, NULL, NULL );
511 bauigel.calc_straight_route( welt->lookup_kartenboden(center+koord::west)->get_pos(), welt->lookup_kartenboden(center+koord::east)->get_pos() );
512 assert(bauigel.get_count()-1 > 1);
513 bauigel.build();
514 // now try to connect one of the corners with a road
515 koord bushalt = koord::invalid, runwaystart, runwayend;
516 koord trypos[4] = { koord(0,0), koord(size.x,0), koord(0,size.y), koord(size.x,size.y) };
517 uint32 length=9999;
518 rotation=-1;
519
520 bauigel.init_builder( way_builder_t::strasse, way_builder_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), type_flat ), tunnel_builder_t::get_tunnel_desc(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()), bridge_builder_t::find_bridge(road_wt,road_vehicle->get_topspeed(),welt->get_timeline_year_month()) );
521 bauigel.set_keep_existing_faster_ways(true);
522 bauigel.set_keep_city_roads(true);
523 bauigel.set_maximum(10000);
524
525 // find the closest one to town ...
526 for( int i=0; i<4; i++ ) {
527 bushalt = pos+trypos[i];
528 bauigel.calc_route(welt->lookup_kartenboden(bushalt)->get_pos(),welt->lookup_kartenboden(town_road)->get_pos());
529 // no road => try next
530 if( bauigel.get_count() >= 2 && bauigel.get_count() < length+1 ) {
531 rotation = i;
532 length = bauigel.get_count()-1;
533 }
534 }
535
536 if(rotation==-1) {
537 // if we every get here that means no connection road => remove airport
538 welt->lookup_kartenboden(center+koord::north)->remove_everything_from_way( this, air_wt, ribi_t::none );
539 welt->lookup_kartenboden(center+koord::south)->remove_everything_from_way( this, air_wt, ribi_t::none );
540 welt->lookup_kartenboden(center+koord::west)->remove_everything_from_way( this, air_wt, ribi_t::none );
541 welt->lookup_kartenboden(center+koord::east)->remove_everything_from_way( this, air_wt, ribi_t::none );
542 welt->lookup_kartenboden(center)->remove_everything_from_way( this, air_wt, ribi_t::all );
543 return halthandle_t();
544 }
545
546 bushalt = pos+trypos[rotation];
547 bauigel.calc_route(welt->lookup_kartenboden(bushalt)->get_pos(),welt->lookup_kartenboden(town_road)->get_pos());
548 bauigel.build();
549 // now the busstop (our next hub ... )
550 const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX );
551 // get an airport name (even though the hub is the bus stop ... )
552 // now built the bus stop
553 if(!call_general_tool( TOOL_BUILD_STATION, bushalt, busstop_desc->get_name() )) {
554 welt->lookup_kartenboden(center+koord::north)->remove_everything_from_way( this, air_wt, ribi_t::none );
555 welt->lookup_kartenboden(center+koord::south)->remove_everything_from_way( this, air_wt, ribi_t::none );
556 welt->lookup_kartenboden(center+koord::west)->remove_everything_from_way( this, air_wt, ribi_t::none );
557 welt->lookup_kartenboden(center+koord::east)->remove_everything_from_way( this, air_wt, ribi_t::none );
558 welt->lookup_kartenboden(center)->remove_everything_from_way( this, air_wt, ribi_t::all );
559 return halthandle_t();
560 }
561 // and change name to airport ...
562 grund_t *gr = welt->lookup_kartenboden(bushalt);
563 halthandle_t halt = gr ? gr->get_halt() : halthandle_t();
564 if (halt.is_bound()) { // it should be, but avoid crashes
565 char* const name = halt->create_name(bushalt, "Airport");
566 halt->set_name( name );
567 free(name);
568 }
569 // built also runway now ...
570 bauigel.init_builder( way_builder_t::luft, runway_desc, NULL, NULL );
571 bauigel.calc_straight_route( welt->lookup_kartenboden(pos+trypos[rotation==0?3:0])->get_pos(), welt->lookup_kartenboden(pos+trypos[1+(rotation&1)])->get_pos() );
572 assert(bauigel.get_count()-1 > 1);
573 bauigel.build();
574 // now the airstops (only on single tiles, this will always work
575 const building_desc_t* airstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, air_wt, welt->get_timeline_year_month(), 0 );
576 for( int i=0; i<4; i++ ) {
577 if( koord_distance(center+koord::nsew[i],bushalt)==1 && ribi_t::is_single( welt->lookup_kartenboden(center+koord::nsew[i])->get_weg_ribi_unmasked(air_wt) ) ) {
578 call_general_tool( TOOL_BUILD_STATION, center+koord::nsew[i], airstop_desc->get_name() );
579 }
580 }
581 // and now the one far away ...
582 for( int i=0; i<4; i++ ) {
583 if( koord_distance(center+koord::nsew[i],bushalt)>1 && ribi_t::is_single( welt->lookup_kartenboden(center+koord::nsew[i])->get_weg_ribi_unmasked(air_wt) ) ) {
584 call_general_tool( TOOL_BUILD_STATION, center+koord::nsew[i], airstop_desc->get_name() );
585 }
586 }
587 // success
588 return halt;
589 }
590
591
find_airport_pos(karte_t * welt,const stadt_t * s)592 static koord find_airport_pos(karte_t* welt, const stadt_t *s )
593 {
594 koord bestpos = koord::invalid, k;
595 sint32 bestdist = 999999;
596
597 // try to find an airport place as close to the city as possible
598 for( k.y=max(6,s->get_linksoben().y-10); k.y<=min(welt->get_size().y-3-6,s->get_rechtsunten().y+10); k.y++ ) {
599 for( k.x=max(6,s->get_linksoben().x-25); k.x<=min(welt->get_size().x-3-6,s->get_rechtsunten().x+10); k.x++ ) {
600 sint32 testdist = koord_distance( k, s->get_pos() );
601 if( testdist<bestdist ) {
602 if( k.x+2<s->get_linksoben().x || k.y+2<s->get_linksoben().y || k.x>=s->get_rechtsunten().x || k.y>=s->get_rechtsunten().y ) {
603 // malus for out of town
604 testdist += 5;
605 }
606 if( testdist<bestdist && welt->square_is_free( k, 3, 3, NULL, ALL_CLIMATES ) ) {
607 bestpos = k;
608 bestdist = testdist;
609 }
610 }
611 }
612 }
613 return bestpos;
614 }
615
616
617 /* build airports and planes
618 * @author prissi
619 */
create_air_transport_vehikel(const stadt_t * start_stadt,const stadt_t * end_stadt)620 bool ai_passenger_t::create_air_transport_vehikel(const stadt_t *start_stadt, const stadt_t *end_stadt)
621 {
622 const vehicle_desc_t *v_desc = vehikel_search(air_wt, 10, 900, goods_manager_t::passengers, false);
623 if(v_desc==NULL) {
624 // no aircraft there
625 return false;
626 }
627
628 if( convoihandle_t::is_exhausted() ) {
629 // too many convois => cannot do anything about this ...
630 return false;
631 }
632
633 halthandle_t start_hub = get_our_hub( start_stadt );
634 halthandle_t start_connect_hub;
635 koord start_airport;
636 if(start_hub.is_bound()) {
637 if( (start_hub->get_station_type()&haltestelle_t::airstop)==0 ) {
638 start_connect_hub = start_hub;
639 start_hub = halthandle_t();
640 // is there already one airport next to this town?
641 FOR(vector_tpl<haltestelle_t::connection_t>, const& i, start_connect_hub->get_pax_connections()) {
642 halthandle_t const h = i.halt;
643 if( h->get_station_type()&haltestelle_t::airstop ) {
644 start_hub = h;
645 break;
646 }
647 }
648 }
649 else {
650 start_airport = start_hub->get_basis_pos();
651 }
652 }
653 // find an airport place
654 if(!start_hub.is_bound()) {
655 start_airport = find_airport_pos( welt, start_stadt );
656 if(start_airport==koord::invalid) {
657 // sorry, no suitable place
658 return false;
659 }
660 }
661 // same for end
662 halthandle_t end_hub = get_our_hub( end_stadt );
663 halthandle_t end_connect_hub;
664 koord end_airport;
665 if(end_hub.is_bound()) {
666 if( (end_hub->get_station_type()&haltestelle_t::airstop)==0 ) {
667 end_connect_hub = end_hub;
668 end_hub = halthandle_t();
669 // is there already one airport next to this town?
670 FOR(vector_tpl<haltestelle_t::connection_t>, const& i, end_connect_hub->get_pax_connections()) {
671 halthandle_t const h = i.halt;
672 if( h->get_station_type()&haltestelle_t::airstop ) {
673 start_hub = h;
674 break;
675 }
676 }
677 }
678 else {
679 end_airport = end_hub->get_basis_pos();
680 }
681 }
682 if(!end_hub.is_bound()) {
683 // find an airport place
684 end_airport = find_airport_pos( welt, end_stadt );
685 if(end_airport==koord::invalid) {
686 // sorry, no suitable place
687 return false;
688 }
689 }
690 // eventually construct them
691 if(start_airport!=koord::invalid && end_airport!=koord::invalid) {
692 // build the airport if necessary
693 if(!start_hub.is_bound()) {
694 start_hub = build_airport(start_stadt, start_airport, true);
695 if(!start_hub.is_bound()) {
696 return false;
697 }
698 start_connect_hub = get_our_hub( start_stadt );
699 if(!start_connect_hub.is_bound()) {
700 koord sch = find_place_for_hub( start_stadt );
701 // probably we must construct a city hub, since the airport is outside of the city limits
702 const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX );
703 call_general_tool( TOOL_BUILD_STATION, sch, busstop_desc->get_name() );
704 start_connect_hub = get_our_hub( start_stadt );
705 assert( start_connect_hub.is_bound() );
706 }
707 }
708 if(!end_hub.is_bound()) {
709 end_hub = build_airport(end_stadt, end_airport, true);
710 if(!end_hub.is_bound()) {
711 if (start_hub->get_pax_connections().empty()) {
712 // remove airport busstop
713 welt->lookup_kartenboden(start_hub->get_basis_pos())->remove_everything_from_way( this, road_wt, ribi_t::none );
714 koord center = start_hub->get_basis_pos() + koord( welt->lookup_kartenboden(start_hub->get_basis_pos())->get_weg_ribi_unmasked( air_wt ) );
715 // now the remaining taxi-/runways
716 for( sint16 y=center.y-1; y<=center.y+1; y++ ) {
717 for( sint16 x=center.x-1; x<=center.x+1; x++ ) {
718 welt->lookup_kartenboden(koord(x,y))->remove_everything_from_way( this, air_wt, ribi_t::none );
719 }
720 }
721 }
722 return false;
723 }
724 end_connect_hub = get_our_hub( end_stadt );
725 if(!end_connect_hub.is_bound()) {
726 koord ech = find_place_for_hub( end_stadt );
727 // probably we must construct a city hub, since the airport is outside of the city limits
728 const building_desc_t* busstop_desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX );
729 call_general_tool( TOOL_BUILD_STATION, ech, busstop_desc->get_name() );
730 end_connect_hub = get_our_hub( end_stadt );
731 assert( end_connect_hub.is_bound() );
732 }
733 }
734 }
735 // now we have airports (albeit first tile is a bus stop)
736 const grund_t *start = start_hub->find_matching_position(air_wt);
737 const grund_t *end = end_hub->find_matching_position(air_wt);
738
739 // since 86.01 we use lines for vehicles ...
740 schedule_t *schedule=new airplane_schedule_t();
741 schedule->append( start, 0, 0 );
742 schedule->append( end, 90, 0 );
743 schedule->set_current_stop( 1 );
744 schedule->finish_editing();
745 linehandle_t line=simlinemgmt.create_line(simline_t::airline,this,schedule);
746 delete schedule;
747
748 // now create one plane
749 vehicle_t* v = vehicle_builder_t::build( start->get_pos(), this, NULL, v_desc);
750 convoi_t* cnv = new convoi_t(this);
751 cnv->set_name(v->get_desc()->get_name());
752 cnv->add_vehikel( v );
753 cnv->set_line(line);
754 cnv->start();
755
756 // eventually build a airport shuttle bus ...
757 if(start_connect_hub.is_bound() && start_connect_hub!=start_hub) {
758 koord stops[2] = { start_hub->get_basis_pos(), start_connect_hub->get_basis_pos() };
759 create_bus_transport_vehikel( stops[1], 1, stops, 2, false );
760 }
761
762 // eventually build a airport shuttle bus ...
763 if(end_connect_hub.is_bound() && end_connect_hub!=end_hub) {
764 koord stops[2] = { end_hub->get_basis_pos(), end_connect_hub->get_basis_pos() };
765 create_bus_transport_vehikel( stops[1], 1, stops, 2, false );
766 }
767
768 return true;
769 }
770
771
772 /* creates a more general road transport
773 * @author prissi
774 */
create_bus_transport_vehikel(koord startpos2d,int anz_vehikel,koord * stops,int count,bool do_wait)775 void ai_passenger_t::create_bus_transport_vehikel(koord startpos2d,int anz_vehikel,koord *stops,int count,bool do_wait)
776 {
777 DBG_MESSAGE("ai_passenger_t::create_bus_transport_vehikel()","bus at (%i,%i)",startpos2d.x,startpos2d.y);
778 // now start all vehicle one field before, so they load immediately
779 koord3d startpos = welt->lookup_kartenboden(startpos2d)->get_pos();
780
781 // since 86.01 we use lines for road vehicles ...
782 schedule_t *schedule=new truck_schedule_t();
783 // do not start at current stop => wont work ...
784 for(int j=0; j<count; j++) {
785 schedule->append(welt->lookup_kartenboden(stops[j]), j == 0 || !do_wait ? 0 : 10);
786 }
787 schedule->set_current_stop( stops[0]==startpos2d );
788 schedule->finish_editing();
789 linehandle_t line=simlinemgmt.create_line(simline_t::truckline,this,schedule);
790 delete schedule;
791
792 // now create all vehicles as convois
793 for(int i=0; i<anz_vehikel; i++) {
794 vehicle_t* v = vehicle_builder_t::build(startpos, this, NULL, road_vehicle);
795 if( convoihandle_t::is_exhausted() ) {
796 // too many convois => cannot do anything about this ...
797 return;
798 }
799 convoi_t* cnv = new convoi_t(this);
800 // V.Meyer: give the new convoi name from first vehicle
801 cnv->set_name(v->get_desc()->get_name());
802 cnv->add_vehikel( v );
803
804 cnv->set_line(line);
805 cnv->start();
806 }
807 }
808
809
810 /* now we follow all adjacent streets recursively and mark them
811 * if they below to this stop, then we continue
812 */
walk_city(linehandle_t const line,grund_t * const start,int const limit)813 void ai_passenger_t::walk_city(linehandle_t const line, grund_t* const start, int const limit)
814 {
815 //maximum number of stops reached?
816 if(line->get_schedule()->get_count()>=limit) {
817 return;
818 }
819
820 ribi_t::ribi ribi = start->get_weg_ribi(road_wt);
821
822 for(int r=0; r<4; r++) {
823
824 // a way in our direction?
825 if( (ribi & ribi_t::nsew[r])==0 ) {
826 continue;
827 }
828
829 // ok, if connected, not marked, and not owner by somebody else
830 grund_t *to;
831 if( start->get_neighbour(to, road_wt, ribi_t::nsew[r] ) && !marker->is_marked(to) && check_owner(to->obj_bei(0)->get_owner(),this) ) {
832
833 // ok, here is a valid street tile
834 marker->mark(to);
835
836 // can built a station here
837 if( ribi_t::is_straight(to->get_weg_ribi(road_wt)) ) {
838
839 // find out how many tiles we have covered already
840 int covered_tiles=0;
841 int house_tiles=0;
842 uint16 const cov = welt->get_settings().get_station_coverage();
843 for (sint16 y = to->get_pos().y - cov; y <= to->get_pos().y + cov + 1; ++y) {
844 for (sint16 x = to->get_pos().x - cov; x <= to->get_pos().x + cov + 1; ++x) {
845 const planquadrat_t *pl = welt->access(koord(x,y));
846 // check, if we have a passenger stop already here
847 if(pl && pl->get_haltlist_count()>0) {
848 const halthandle_t *hl=pl->get_haltlist();
849 for( uint8 own=0; own<pl->get_haltlist_count(); own++ ) {
850 if( hl[own]->is_enabled(goods_manager_t::INDEX_PAS) ) {
851 // our stop => nothing to do
852 #if AUTOJOIN_PUBLIC
853 // we leave also public stops alone
854 if( hl[own]->get_owner()==this || hl[own]->get_owner()==welt->get_public_player() ) {
855 #else
856 if( hl[own]->get_owner()==this ) {
857 #endif
858 covered_tiles ++;
859 break;
860 }
861 }
862 }
863 }
864 // check for houses
865 if(pl && pl->get_kartenboden()->get_typ()==grund_t::fundament) {
866 house_tiles++;
867 }
868 }
869 }
870 // now decide, if we build here
871 // just using the ration of covered tiles versus house tiles
872 int const max_tiles = cov * 2 + 1;
873 if( covered_tiles<(max_tiles*max_tiles)/3 && house_tiles>=3 ) {
874 // ok, lets do it
875 const building_desc_t* bs = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX);
876 if( call_general_tool( TOOL_BUILD_STATION, to->get_pos().get_2d(), bs->get_name() ) ) {
877 //add to line
878 line->get_schedule()->append(to,0); // no need to register it yet; done automatically, when convois will be assigned
879 }
880 }
881 // start road, but no houses anywhere => stop searching
882 if(house_tiles==0) {
883 return;
884 }
885 }
886 // now do recursion
887 walk_city( line, to, limit );
888 }
889 }
890 }
891
892
893 /* tries to cover a city with bus stops that does not overlap much and cover as much as possible
894 * returns the line created, if successful
895 */
896 void ai_passenger_t::cover_city_with_bus_route(koord start_pos, int number_of_stops)
897 {
898 if( convoihandle_t::is_exhausted() ) {
899 // too many convois => cannot do anything about this ...
900 return;
901 }
902
903 // nothing in lists
904 marker = &marker_t::instance(welt->get_size().x, welt->get_size().y);
905
906 // and init all stuff for recursion
907 grund_t *start = welt->lookup_kartenboden(start_pos);
908 linehandle_t line = simlinemgmt.create_line( simline_t::truckline,this, new truck_schedule_t() );
909 line->get_schedule()->append(start,0);
910
911 // now create a line
912 walk_city( line, start, number_of_stops );
913 line->get_schedule()->finish_editing();
914
915 road_vehicle = vehikel_search( road_wt, 1, 50, goods_manager_t::passengers, false);
916 if( line->get_schedule()->get_count()>1 ) {
917 // success: add a bus to the line
918 vehicle_t* v = vehicle_builder_t::build(start->get_pos(), this, NULL, road_vehicle);
919 convoi_t* cnv = new convoi_t(this);
920
921 cnv->set_name(v->get_desc()->get_name());
922 cnv->add_vehikel( v );
923
924 cnv->set_line(line);
925 cnv->start();
926 }
927 else {
928 simlinemgmt.delete_line( line );
929 }
930 marker = NULL;
931 }
932
933
934 void ai_passenger_t::step()
935 {
936 // needed for schedule of stops ...
937 player_t::step();
938
939 if(!active) {
940 // I am off ...
941 return;
942 }
943
944 // one route per month ...
945 if( welt->get_steps() < next_construction_steps ) {
946 return;
947 }
948
949 switch(state) {
950 case NR_INIT:
951 {
952 // time to update hq?
953 built_update_headquarter();
954
955 // assume fail
956 state = CHECK_CONVOI;
957
958 /* if we have this little money, we do nothing
959 * The second condition may happen due to extensive replacement operations;
960 * in such a case it is save enough to expand anyway.
961 */
962 if(!(finance->get_account_balance()>0 || finance->has_money_or_assets()) ) {
963 return;
964 }
965
966 const weighted_vector_tpl<stadt_t*>& staedte = welt->get_cities();
967 int count = staedte.get_count();
968 int offset = (count>1) ? simrand(count-1) : 0;
969 // start with previous target
970 const stadt_t* last_start_stadt=start_stadt;
971 start_stadt = end_stadt;
972 end_stadt = NULL;
973 end_attraction = NULL;
974 ziel = NULL;
975 platz2 = koord::invalid;
976 // if no previous town => find one
977 if(start_stadt==NULL) {
978 // larger start town preferred
979 start_stadt = pick_any_weighted(staedte);
980 offset = staedte.index_of(start_stadt);
981 }
982 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using city %s for start",start_stadt->get_name());
983 const halthandle_t start_halt = get_our_hub(start_stadt);
984 // find starting place
985
986 if(!start_halt.is_bound()) {
987 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","new_hub");
988 }
989 platz1 = start_halt.is_bound() ? start_halt->get_basis_pos() : find_place_for_hub( start_stadt );
990 if(platz1==koord::invalid) {
991 return;
992 }
993 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using place (%i,%i) for start",platz1.x,platz1.y);
994
995 if(count==1 || simrand(3)==0) {
996 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","searching attraction");
997 // 25 % of all connections are tourist attractions
998 const weighted_vector_tpl<gebaeude_t*> &attractions = welt->get_attractions();
999 // this way, we are sure, our factory is connected to this town ...
1000 const vector_tpl<stadt_t::factory_entry_t> &fabriken = start_stadt->get_target_factories_for_pax().get_entries();
1001 unsigned last_dist = 0xFFFFFFFF;
1002 bool ausflug=simrand(2)!=0; // holidays first ...
1003 int ziel_count=ausflug?attractions.get_count():fabriken.get_count();
1004 for( int i=0; i<ziel_count; i++ ) {
1005 unsigned dist;
1006 koord pos, size;
1007 if(ausflug) {
1008 const gebaeude_t* a = attractions[i];
1009 if (a->get_mail_level() <= 25) {
1010 // not a good object to go to ...
1011 continue;
1012 }
1013 pos = a->get_pos().get_2d();
1014 size = a->get_tile()->get_desc()->get_size(a->get_tile()->get_layout());
1015 }
1016 else {
1017 const fabrik_t* f = fabriken[i].factory;
1018 const factory_desc_t *const desc = f->get_desc();
1019 if (( desc->get_pax_demand()==65535 ? desc->get_pax_level() : desc->get_pax_demand() ) <= 10) {
1020 // not a good object to go to ... we want more action ...
1021 continue;
1022 }
1023 pos = f->get_pos().get_2d();
1024 size = f->get_desc()->get_building()->get_size(f->get_rotate());
1025 }
1026 const stadt_t *next_town = welt->find_nearest_city(pos);
1027 if(next_town==NULL || start_stadt==next_town) {
1028 // this is either a town already served (so we do not create a new hub)
1029 // or a lonely point somewhere
1030 // in any case we do not want to serve this location already
1031 uint16 const c = welt->get_settings().get_station_coverage();
1032 koord const cov = koord(c, c);
1033 koord test_platz=find_area_for_hub(pos-cov,pos+size+cov,pos);
1034 if( !get_halt(test_platz).is_bound() ) {
1035 // not served
1036 dist = koord_distance(platz1,test_platz);
1037 if(dist+simrand(50)<last_dist && dist>3) {
1038 // but closer than the others
1039 if(ausflug) {
1040 end_attraction = attractions[i];
1041 }
1042 else {
1043 ziel = fabriken[i].factory;
1044 }
1045 last_dist = dist;
1046 platz2 = test_platz;
1047 }
1048 }
1049 }
1050 }
1051 // test for success
1052 if(platz2!=koord::invalid) {
1053 // found something
1054 state = NR_SAMMLE_ROUTEN;
1055 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","decision: %s wants to built network between %s and %s",get_name(),start_stadt->get_name(),ausflug?end_attraction->get_tile()->get_desc()->get_name():ziel->get_name());
1056 }
1057 }
1058 else {
1059 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","searching town");
1060 int last_dist = 9999999;
1061 // find a good route
1062 for( int i=0; i<count; i++ ) {
1063 const int nr = (i+offset)%count;
1064 const stadt_t* cur = staedte[nr];
1065 if(cur!=last_start_stadt && cur!=start_stadt) {
1066 halthandle_t end_halt = get_our_hub(cur);
1067 int dist = koord_distance(platz1,cur->get_pos());
1068 if( end_halt.is_bound() && is_connected(platz1,end_halt->get_basis_pos(),goods_manager_t::passengers) ) {
1069 // already connected
1070 continue;
1071 }
1072 // check if more close
1073 if( dist<last_dist ) {
1074 end_stadt = cur;
1075 last_dist = dist;
1076 }
1077 }
1078 }
1079 // ok, found two cities
1080 if(start_stadt!=NULL && end_stadt!=NULL) {
1081 state = NR_SAMMLE_ROUTEN;
1082 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","%s wants to built network between %s and %s",get_name(),start_stadt->get_name(),end_stadt->get_name());
1083 }
1084 }
1085 }
1086 break;
1087
1088 // so far only busses
1089 case NR_SAMMLE_ROUTEN:
1090 {
1091 //
1092 koord end_hub_pos = koord::invalid;
1093 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","Find hub");
1094 // also for target (if not tourist attraction!)
1095 if(end_stadt!=NULL) {
1096 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","try to built connect to city %p", end_stadt );
1097 // target is town
1098 halthandle_t h = get_our_hub(end_stadt);
1099 if(h.is_bound()) {
1100 end_hub_pos = h->get_basis_pos();
1101 }
1102 else {
1103 end_hub_pos = find_place_for_hub( end_stadt );
1104 }
1105 }
1106 else {
1107 // already found place
1108 end_hub_pos = platz2;
1109 }
1110 // was successful?
1111 if(end_hub_pos!=koord::invalid) {
1112 // ok, now we check the vehicle
1113 platz2 = end_hub_pos;
1114 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","hub found -> NR_BAUE_ROUTE1");
1115 state = NR_BAUE_ROUTE1;
1116 }
1117 else {
1118 // no success
1119 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","no suitable hub found");
1120 end_stadt = NULL;
1121 state = CHECK_CONVOI;
1122 }
1123 }
1124 break;
1125
1126 // get a suitable vehicle
1127 case NR_BAUE_ROUTE1:
1128 // wait for construction semaphore
1129 {
1130 // we want the fastest we can get!
1131 road_vehicle = vehikel_search( road_wt, 50, 80, goods_manager_t::passengers, false);
1132 if(road_vehicle!=NULL) {
1133 // find the best => AI will never survive
1134 // road_weg = way_builder_t::weg_search( road_wt, road_vehicle->get_topspeed(), welt->get_timeline_year_month(),type_flat );
1135 // find the really cheapest road
1136 road_weg = way_builder_t::weg_search( road_wt, 10, welt->get_timeline_year_month(), type_flat );
1137 state = NR_BAUE_STRASSEN_ROUTE;
1138 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using %s on %s",road_vehicle->get_name(),road_weg->get_name());
1139 }
1140 else {
1141 // no success
1142 end_stadt = NULL;
1143 state = CHECK_CONVOI;
1144 }
1145 }
1146 break;
1147
1148 // built a simple road (no bridges, no tunnels)
1149 case NR_BAUE_STRASSEN_ROUTE:
1150 {
1151 state = NR_BAUE_WATER_ROUTE; // assume failure
1152 if( !ai_t::road_transport ) {
1153 // no overland bus lines
1154 break;
1155 }
1156 const building_desc_t* bs = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX);
1157 if(bs && create_simple_road_transport(platz1, koord(1,1),platz2,koord(1,1),road_weg) ) {
1158 // since the road may have led to a crossing at the intended stop position ...
1159 bool ok = true;
1160 if( !get_halt(platz1).is_bound() ) {
1161 if( !call_general_tool( TOOL_BUILD_STATION, platz1, bs->get_name() ) ) {
1162 platz1 = find_area_for_hub( platz1-koord(2,2), platz1+koord(2,2), platz1 );
1163 ok = call_general_tool( TOOL_BUILD_STATION, platz1, bs->get_name() );
1164 }
1165 }
1166 if( ok ) {
1167 if( !get_halt(platz2).is_bound() ) {
1168 if( !call_general_tool( TOOL_BUILD_STATION, platz2, bs->get_name() ) ) {
1169 platz2 = find_area_for_hub( platz2-koord(2,2), platz2+koord(2,2), platz2 );
1170 ok = call_general_tool( TOOL_BUILD_STATION, platz2, bs->get_name() );
1171 }
1172 }
1173 }
1174 // still continue?
1175 if(ok) {
1176 koord list[2]={ platz1, platz2 };
1177 // wait only, if target is not a hub but an attraction/factory
1178 create_bus_transport_vehikel(platz1,1,list,2,end_stadt==NULL);
1179 state = NR_SUCCESS;
1180 // tell the player
1181 cbuffer_t buf;
1182 if(end_attraction!=NULL) {
1183 platz1 = end_attraction->get_pos().get_2d();
1184 buf.printf(translator::translate("%s now\noffers bus services\nbetween %s\nand attraction\n%s\nat (%i,%i).\n"), get_name(), start_stadt->get_name(), make_single_line_string(translator::translate(end_attraction->get_tile()->get_desc()->get_name()),2), platz1.x, platz1.y );
1185 end_stadt = start_stadt;
1186 }
1187 else if(ziel!=NULL) {
1188 platz1 = ziel->get_pos().get_2d();
1189 buf.printf( translator::translate("%s now\noffers bus services\nbetween %s\nand factory\n%s\nat (%i,%i).\n"), get_name(), start_stadt->get_name(), make_single_line_string(translator::translate(ziel->get_name()),2), platz1.x, platz1.y );
1190 end_stadt = start_stadt;
1191 }
1192 else {
1193 buf.printf( translator::translate("Travellers now\nuse %s's\nbusses between\n%s \nand %s.\n"), get_name(), start_stadt->get_name(), end_stadt->get_name() );
1194 // add two intown routes
1195 cover_city_with_bus_route(platz1, 6);
1196 cover_city_with_bus_route(platz2, 6);
1197 }
1198 welt->get_message()->add_message(buf, platz1, message_t::ai, PLAYER_FLAG|player_nr, road_vehicle->get_base_image());
1199 }
1200 }
1201 }
1202 break;
1203
1204 case NR_BAUE_WATER_ROUTE:
1205 if( !ai_t::ship_transport ) {
1206 // no overland bus lines
1207 state = NR_BAUE_AIRPORT_ROUTE;
1208 break;
1209 }
1210 if( end_attraction == NULL && ship_transport &&
1211 create_water_transport_vehikel(start_stadt, end_stadt ? end_stadt->get_pos() : ziel->get_pos().get_2d())) {
1212 // add two intown routes
1213 cover_city_with_bus_route( get_our_hub(start_stadt)->get_basis_pos(), 6);
1214 if(end_stadt!=NULL) {
1215 cover_city_with_bus_route( get_our_hub(end_stadt)->get_basis_pos(), 6);
1216 }
1217 else {
1218 // start again with same town
1219 end_stadt = start_stadt;
1220 }
1221 cbuffer_t buf;
1222 buf.printf( translator::translate("Ferry service by\n%s\nnow between\n%s \nand %s.\n"), get_name(), start_stadt->get_name(), end_stadt->get_name() );
1223 welt->get_message()->add_message(buf, end_stadt->get_pos(), message_t::ai, PLAYER_FLAG | player_nr, road_vehicle->get_base_image());
1224 state = NR_SUCCESS;
1225 }
1226 else {
1227 if( end_attraction==NULL && ziel==NULL ) {
1228 state = NR_BAUE_AIRPORT_ROUTE;
1229 }
1230 else {
1231 state = NR_BAUE_CLEAN_UP;
1232 }
1233 }
1234 break;
1235
1236 // despite its name: try airplane
1237 case NR_BAUE_AIRPORT_ROUTE:
1238 // try airline (if we are wealthy enough) ...
1239 if( !air_transport || finance->get_history_com_month(1, ATC_CASH) < finance->get_starting_money() ||
1240 !end_stadt || !create_air_transport_vehikel( start_stadt, end_stadt ) ) {
1241 state = NR_BAUE_CLEAN_UP;
1242 }
1243 else {
1244 // add two intown routes
1245 cover_city_with_bus_route( get_our_hub(start_stadt)->get_basis_pos(), 6);
1246 cover_city_with_bus_route( get_our_hub(end_stadt)->get_basis_pos(), 6);
1247 cbuffer_t buf;
1248 buf.printf( translator::translate("Airline service by\n%s\nnow between\n%s \nand %s.\n"), get_name(), start_stadt->get_name(), end_stadt->get_name() );
1249 welt->get_message()->add_message(buf, end_stadt->get_pos(), message_t::ai, PLAYER_FLAG | player_nr, road_vehicle->get_base_image());
1250 state = NR_SUCCESS;
1251 }
1252 break;
1253
1254 // remove marker etc.
1255 case NR_BAUE_CLEAN_UP:
1256 state = CHECK_CONVOI;
1257 end_stadt = NULL; // otherwise it may always try to built the same route!
1258 break;
1259
1260 // successful construction
1261 case NR_SUCCESS:
1262 {
1263 state = CHECK_CONVOI;
1264 next_construction_steps = welt->get_steps() + simrand( construction_speed/16 );
1265 }
1266 break;
1267
1268
1269 // add vehicles to crowded lines
1270 case CHECK_CONVOI:
1271 {
1272 // next time: do something different
1273 state = NR_INIT;
1274 next_construction_steps = welt->get_steps() + simrand( ai_t::construction_speed ) + 25;
1275
1276 vector_tpl<linehandle_t> lines(0);
1277 simlinemgmt.get_lines( simline_t::line, &lines);
1278 const uint32 offset = simrand(lines.get_count());
1279 for (uint32 i = 0; i<lines.get_count(); i++ ) {
1280 linehandle_t line = lines[(i+offset)%lines.get_count()];
1281 if(line->get_linetype()!=simline_t::airline && line->get_linetype()!=simline_t::truckline) {
1282 continue;
1283 }
1284
1285 // remove empty lines
1286 if(line->count_convoys()==0) {
1287 simlinemgmt.delete_line(line);
1288 break;
1289 }
1290
1291 // avoid empty schedule ?!?
1292 assert(!line->get_schedule()->empty());
1293
1294 // made loss with this line
1295 if(line->get_finance_history(0,LINE_PROFIT)<0) {
1296 // try to update the vehicles
1297 if(welt->use_timeline() && line->count_convoys()>1) {
1298 // do not update unimportant lines with single vehicles
1299 slist_tpl <convoihandle_t> obsolete;
1300 uint32 capacity = 0;
1301 for( uint i=0; i<line->count_convoys(); i++ ) {
1302 convoihandle_t cnv = line->get_convoy(i);
1303 if(cnv->has_obsolete_vehicles()) {
1304 obsolete.append(cnv);
1305 capacity += cnv->front()->get_desc()->get_capacity();
1306 }
1307 }
1308 if(capacity>0) {
1309 // now try to find new vehicle
1310 vehicle_t const& v = *line->get_convoy(0)->front();
1311 waytype_t const wt = v.get_waytype();
1312 vehicle_desc_t const* const v_desc = vehicle_builder_t::vehikel_search(wt, welt->get_current_month(), 50, welt->get_average_speed(wt), goods_manager_t::passengers, false, true);
1313 if (!v_desc->is_retired(welt->get_current_month()) && v_desc != v.get_desc()) {
1314 // there is a newer one ...
1315 for( uint32 new_capacity=0; capacity>new_capacity; new_capacity+=v_desc->get_capacity()) {
1316 if( convoihandle_t::is_exhausted() ) {
1317 // too many convois => cannot do anything about this ...
1318 break;
1319 }
1320 vehicle_t* v = vehicle_builder_t::build( line->get_schedule()->entries[0].pos, this, NULL, v_desc );
1321 convoi_t* new_cnv = new convoi_t(this);
1322 new_cnv->set_name( v->get_desc()->get_name() );
1323 new_cnv->add_vehikel( v );
1324 new_cnv->set_line(line);
1325 new_cnv->start();
1326 }
1327 // delete all old convois
1328 while(!obsolete.empty()) {
1329 obsolete.remove_first()->self_destruct();
1330 }
1331 return;
1332 }
1333 }
1334 }
1335 }
1336 // next: check for stuck convois ...
1337
1338 sint64 free_cap = line->get_finance_history(0,LINE_CAPACITY);
1339 sint64 used_cap = line->get_finance_history(0,LINE_TRANSPORTED_GOODS);
1340
1341 if(free_cap+used_cap==0) {
1342 continue;
1343 }
1344
1345 sint32 ratio = (sint32)((free_cap*100l)/(free_cap+used_cap));
1346
1347 // next: check for overflowing lines, i.e. running with 3/4 of the capacity
1348 if( ratio<10 && !convoihandle_t::is_exhausted() ) {
1349 // else add the first convoi again
1350 vehicle_t* const v = vehicle_builder_t::build(line->get_schedule()->entries[0].pos, this, NULL, line->get_convoy(0)->front()->get_desc());
1351 convoi_t* new_cnv = new convoi_t(this);
1352 new_cnv->set_name( v->get_desc()->get_name() );
1353 new_cnv->add_vehikel( v );
1354 new_cnv->set_line( line );
1355 // on waiting line, wait at alternating stations for load balancing
1356 if( line->get_schedule()->entries[1].minimum_loading==90 && line->get_linetype()!=simline_t::truckline && (line->count_convoys()&1)==0 ) {
1357 new_cnv->get_schedule()->entries[0].minimum_loading = 90;
1358 new_cnv->get_schedule()->entries[1].minimum_loading = 0;
1359 }
1360 new_cnv->start();
1361 return;
1362 }
1363
1364 // next: check for too many cars, i.e. running with too many cars
1365 if( ratio>40 && line->count_convoys()>1) {
1366 // remove one convoi
1367 line->get_convoy(0)->self_destruct();
1368 return;
1369 }
1370 }
1371 }
1372 break;
1373
1374 default:
1375 DBG_MESSAGE("ai_passenger_t::do_passenger_ki()", "Illegal state %d!", state );
1376 end_stadt = NULL;
1377 state = NR_INIT;
1378 }
1379 }
1380
1381
1382
1383 void ai_passenger_t::rdwr(loadsave_t *file)
1384 {
1385 if( file->is_version_less(102, 2) ) {
1386 // due to an error the player was never saved correctly
1387 player_t::rdwr(file);
1388 return;
1389 }
1390
1391 xml_tag_t t( file, "ai_passenger_t" );
1392
1393 ai_t::rdwr(file);
1394
1395 // then check, if we have to do something or the game is too old ...
1396 if(file->is_version_less(101, 0)) {
1397 // ignore saving, reinit on loading
1398 if( file->is_loading() ) {
1399 next_construction_steps = welt->get_steps()+simrand(ai_t::construction_speed);
1400 }
1401 return;
1402 }
1403
1404 // now save current state ...
1405 file->rdwr_enum(state);
1406 if( file->is_version_less(111, 1) ) {
1407 file->rdwr_long(ai_t::construction_speed);
1408 file->rdwr_bool(air_transport);
1409 file->rdwr_bool(ship_transport);
1410 road_transport = true;
1411 rail_transport = false;
1412 }
1413 platz1.rdwr( file );
1414 platz2.rdwr( file );
1415
1416 if(file->is_saving()) {
1417 // save current pointers
1418 sint32 delta_steps = next_construction_steps-welt->get_steps();
1419 file->rdwr_long(delta_steps);
1420 koord k = start_stadt ? start_stadt->get_pos() : koord::invalid;
1421 k.rdwr(file);
1422 k = end_stadt ? end_stadt->get_pos() : koord::invalid;
1423 k.rdwr(file);
1424 koord3d k3d = end_attraction ? end_attraction->get_pos() : koord3d::invalid;
1425 k3d.rdwr(file);
1426 k3d = ziel ? ziel->get_pos() : koord3d::invalid;
1427 k3d.rdwr(file);
1428 }
1429 else {
1430 // since steps in loaded game == 0
1431 file->rdwr_long(next_construction_steps);
1432 next_construction_steps += welt->get_steps();
1433 // reinit current pointers
1434 koord k;
1435 k.rdwr(file);
1436 start_stadt = welt->find_nearest_city(k);
1437 k.rdwr(file);
1438 end_stadt = welt->find_nearest_city(k);
1439 koord3d k3d;
1440 k3d.rdwr(file);
1441 end_attraction = welt->lookup(k3d) ? welt->lookup(k3d)->find<gebaeude_t>() : NULL;
1442 k3d.rdwr(file);
1443 ziel = fabrik_t::get_fab(k3d.get_2d() );
1444 }
1445 }
1446
1447
1448
1449 /**
1450 * Dealing with stuck or lost vehicles:
1451 * - delete lost ones
1452 * - ignore stuck ones
1453 * @author prissi
1454 * @date 30-Dec-2008
1455 */
1456 void ai_passenger_t::report_vehicle_problem(convoihandle_t cnv,const koord3d ziel)
1457 {
1458 if( cnv->get_state() == convoi_t::NO_ROUTE && this!=welt->get_active_player() ) {
1459 DBG_MESSAGE("ai_passenger_t::report_vehicle_problem","Vehicle %s can't find a route to (%i,%i)!", cnv->get_name(),ziel.x,ziel.y);
1460 cnv->self_destruct();
1461 return;
1462 }
1463 player_t::report_vehicle_problem( cnv, ziel );
1464 }
1465
1466
1467 void ai_passenger_t::finish_rd()
1468 {
1469 road_vehicle = vehikel_search( road_wt, 50, 80, goods_manager_t::passengers, false);
1470 if (road_vehicle == NULL) {
1471 // reset state
1472 end_stadt = NULL;
1473 state = CHECK_CONVOI;
1474 }
1475 }
1476