1 /*
2 * Copyright (c) 1997 - 2001 Hansjoerg Malthaner
3 *
4 * This file is part of the Simutrans project under the artistic licence.
5 * (see licence.txt)
6 *
7 * Ways (Roads, Railways, etc.)
8 *
9 * Hj. Malthaner
10 */
11
12 #include <algorithm>
13
14 #include "../simdebug.h"
15 #include "../simworld.h"
16 #include "../simtool.h"
17 #include "../simmesg.h"
18 #include "../simintr.h"
19 #include "../player/simplay.h"
20 #include "../simplan.h"
21 #include "../simdepot.h"
22
23 #include "wegbauer.h"
24 #include "brueckenbauer.h"
25 #include "tunnelbauer.h"
26
27 #include "../descriptor/way_desc.h"
28 #include "../descriptor/tunnel_desc.h"
29 #include "../descriptor/building_desc.h"
30 #include "../descriptor/crossing_desc.h"
31
32 #include "../boden/wege/strasse.h"
33 #include "../boden/wege/schiene.h"
34 #include "../boden/wege/monorail.h"
35 #include "../boden/wege/maglev.h"
36 #include "../boden/wege/narrowgauge.h"
37 #include "../boden/wege/kanal.h"
38 #include "../boden/wege/runway.h"
39 #include "../boden/brueckenboden.h"
40 #include "../boden/monorailboden.h"
41 #include "../boden/tunnelboden.h"
42 #include "../boden/grund.h"
43
44 #include "../dataobj/environment.h"
45 #include "../dataobj/route.h"
46 #include "../dataobj/marker.h"
47 #include "../dataobj/translator.h"
48 #include "../dataobj/scenario.h"
49
50 #include "../utils/simrandom.h"
51
52 // binary heap, since we only need insert and pop
53 #include "../tpl/binary_heap_tpl.h" // fastest
54
55 #include "../obj/field.h"
56 #include "../obj/gebaeude.h"
57 #include "../obj/bruecke.h"
58 #include "../obj/tunnel.h"
59 #include "../obj/crossing.h"
60 #include "../obj/leitung2.h"
61 #include "../obj/groundobj.h"
62 #include "../obj/wayobj.h"
63
64 #include "../ifc/simtestdriver.h"
65
66 #include "../tpl/stringhashtable_tpl.h"
67
68 #include "../gui/minimap.h" // for debugging
69 #include "../gui/tool_selector.h"
70 #include "../gui/messagebox.h"
71
72 #ifdef DEBUG_ROUTES
73 #include "../simsys.h"
74 #endif
75
76 // built bridges automatically
77 //#define AUTOMATIC_BRIDGES
78
79 // built tunnels automatically
80 //#define AUTOMATIC_TUNNELS
81
82 // lookup also return route and take the better of the two
83 #define REVERSE_CALC_ROUTE_TOO
84
85 karte_ptr_t way_builder_t::welt;
86
87 const way_desc_t *way_builder_t::leitung_desc = NULL;
88
89 static stringhashtable_tpl <const way_desc_t *> desc_table;
90
91
set_default(way_desc_t const * & def,waytype_t const wtyp,systemtype_t const system_type=type_flat,sint32 const speed_limit=1)92 static void set_default(way_desc_t const*& def, waytype_t const wtyp, systemtype_t const system_type = type_flat, sint32 const speed_limit = 1)
93 {
94 def = way_builder_t::weg_search(wtyp, speed_limit, 0, system_type);
95 if (def == NULL) {
96 def = way_builder_t::weg_search(wtyp, 1, 0, type_all);
97 }
98 }
99
100
successfully_loaded()101 bool way_builder_t::successfully_loaded()
102 {
103 // some defaults to avoid hardcoded values
104 set_default(strasse_t::default_strasse, road_wt, type_flat, 50);
105 if( strasse_t::default_strasse == NULL ) {
106 dbg->fatal( "way_builder_t::successfully_loaded()", "No road found at all!" );
107 return false;
108 }
109
110 set_default(schiene_t::default_schiene, track_wt, type_flat, 80);
111 set_default(monorail_t::default_monorail, monorail_wt, type_elevated); // Only elevated?
112 set_default(maglev_t::default_maglev, maglev_wt, type_elevated); // Only elevated?
113 set_default(narrowgauge_t::default_narrowgauge, narrowgauge_wt);
114 set_default(kanal_t::default_kanal, water_wt, type_all); // Also find hidden rivers.
115 set_default(runway_t::default_runway, air_wt, type_runway);
116 set_default(way_builder_t::leitung_desc, powerline_wt);
117
118 return true;
119 }
120
121
register_desc(way_desc_t * desc)122 bool way_builder_t::register_desc(way_desc_t *desc)
123 {
124 if( const way_desc_t *old_desc = desc_table.remove(desc->get_name()) ) {
125 dbg->doubled( "way", desc->get_name() );
126 tool_t::general_tool.remove( old_desc->get_builder() );
127 delete old_desc->get_builder();
128 delete old_desc;
129 }
130
131 if( desc->get_cursor()->get_image_id(1)!=IMG_EMPTY ) {
132 // add the tool
133 tool_build_way_t *tool = new tool_build_way_t();
134 tool->set_icon( desc->get_cursor()->get_image_id(1) );
135 tool->cursor = desc->get_cursor()->get_image_id(0);
136 tool->set_default_param(desc->get_name());
137 tool_t::general_tool.append( tool );
138 desc->set_builder( tool );
139 }
140 else {
141 desc->set_builder( NULL );
142 }
143 desc_table.put(desc->get_name(), desc);
144 return true;
145 }
146
147
get_way_list(const waytype_t wtyp,systemtype_t styp)148 const vector_tpl<const way_desc_t *>& way_builder_t::get_way_list(const waytype_t wtyp, systemtype_t styp)
149 {
150 static vector_tpl<const way_desc_t *> dummy;
151 dummy.clear();
152 const uint16 time = welt->get_timeline_year_month();
153 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
154 way_desc_t const* const test = i.value;
155 if( test->get_wtyp()==wtyp && test->get_styp()== styp && test->is_available(time) && test->get_builder() ) {
156 dummy.append(test);
157 }
158 }
159 return dummy;
160 }
161
162
163 /**
164 * Finds a way with a given speed limit for a given waytype
165 * It finds:
166 * - the slowest way, as fast as speed limit
167 * - if no way faster than speed limit, the fastest way.
168 * The timeline is also respected.
169 * @author prissi, gerw
170 */
weg_search(const waytype_t wtyp,const sint32 speed_limit,const uint16 time,const systemtype_t system_type)171 const way_desc_t* way_builder_t::weg_search(const waytype_t wtyp, const sint32 speed_limit, const uint16 time, const systemtype_t system_type)
172 {
173 const way_desc_t* best = NULL;
174 bool best_allowed = false; // Does the best way fulfil the timeline?
175 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
176 way_desc_t const* const test = i.value;
177 if( ((test->get_wtyp()==wtyp &&
178 (test->get_styp()==system_type || system_type==type_all)) || (test->get_wtyp()==track_wt && test->get_styp()==type_tram && wtyp==tram_wt))
179 && test->get_cursor()->get_image_id(1)!=IMG_EMPTY ) {
180 bool test_allowed = test->get_intro_year_month()<=time && time<test->get_retire_year_month();
181 if( !best_allowed || time==0 || test_allowed ) {
182 if( best==NULL ||
183 ( best->get_topspeed() < test->get_topspeed() && test->get_topspeed() <= speed_limit ) || // closer to desired speed (from the low end)
184 ( speed_limit < best->get_topspeed() && test->get_topspeed() < best->get_topspeed()) || // respects speed_limit better
185 ( time!=0 && !best_allowed && test_allowed) // current choice is actually not really allowed, timewise
186 ) {
187 best = test;
188 best_allowed = test_allowed;
189 }
190 }
191 }
192 }
193 return best;
194 }
195
196
197
get_earliest_way(const waytype_t wtyp)198 const way_desc_t *way_builder_t::get_earliest_way(const waytype_t wtyp)
199 {
200 const way_desc_t *desc = NULL;
201 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
202 way_desc_t const* const test = i.value;
203 if( test->get_wtyp()==wtyp && (desc==NULL || test->get_intro_year_month()<desc->get_intro_year_month()) ) {
204 desc = test;
205 }
206 }
207 return desc;
208 }
209
210
211
get_latest_way(const waytype_t wtyp)212 const way_desc_t *way_builder_t::get_latest_way(const waytype_t wtyp)
213 {
214 const way_desc_t *desc = NULL;
215 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
216 way_desc_t const* const test = i.value;
217 if( test->get_wtyp()==wtyp && (desc==NULL || test->get_retire_year_month()>desc->get_retire_year_month()) ) {
218 desc = test;
219 }
220 }
221 return desc;
222 }
223
224
225 // ture if the way is available with timely
waytype_available(const waytype_t wtyp,uint16 time)226 bool way_builder_t::waytype_available( const waytype_t wtyp, uint16 time )
227 {
228 if( time==0 ) {
229 return true;
230 }
231
232 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
233 way_desc_t const* const test = i.value;
234 if( test->get_wtyp()==wtyp && test->get_intro_year_month()<=time && test->get_retire_year_month()>time ) {
235 return true;
236 }
237 }
238 return false;
239 }
240
241
242
get_desc(const char * way_name,const uint16 time)243 const way_desc_t * way_builder_t::get_desc(const char * way_name, const uint16 time)
244 {
245 //DBG_MESSAGE("way_builder_t::get_desc","return desc for %s in (%i)",way_name, time/12);
246 const way_desc_t *desc = desc_table.get(way_name);
247 if( desc && desc->is_available(time) ) {
248 return desc;
249 }
250 return NULL;
251 }
252
253
254
255 // generates timeline message
new_month()256 void way_builder_t::new_month()
257 {
258 const uint16 current_month = welt->get_timeline_year_month();
259 if(current_month!=0) {
260 // check, what changed
261 slist_tpl <const way_desc_t *> matching;
262 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
263 way_desc_t const* const desc = i.value;
264 cbuffer_t buf;
265
266 const uint16 intro_month = desc->get_intro_year_month();
267 if(intro_month == current_month) {
268 buf.printf( translator::translate("way %s now available:\n"), translator::translate(desc->get_name()) );
269 welt->get_message()->add_message(buf,koord::invalid,message_t::new_vehicle,NEW_VEHICLE,desc->get_image_id(5,0));
270 }
271
272 const uint16 retire_month = desc->get_retire_year_month();
273 if(retire_month == current_month) {
274 buf.printf( translator::translate("way %s cannot longer used:\n"), translator::translate(desc->get_name()) );
275 welt->get_message()->add_message(buf,koord::invalid,message_t::new_vehicle,NEW_VEHICLE,desc->get_image_id(5,0));
276 }
277 }
278
279 }
280 }
281
282
compare_ways(const way_desc_t * a,const way_desc_t * b)283 static bool compare_ways(const way_desc_t* a, const way_desc_t* b)
284 {
285 int cmp = a->get_topspeed() - b->get_topspeed();
286 if(cmp==0) {
287 cmp = (int)a->get_intro_year_month() - (int)b->get_intro_year_month();
288 }
289 if(cmp==0) {
290 cmp = strcmp(a->get_name(), b->get_name());
291 }
292 return cmp<0;
293 }
294
295
296 /**
297 * Fill menu with icons of given waytype, return number of added entries
298 * @author Hj. Malthaner/prissi/dariok
299 */
fill_menu(tool_selector_t * tool_selector,const waytype_t wtyp,const systemtype_t styp,sint16)300 void way_builder_t::fill_menu(tool_selector_t *tool_selector, const waytype_t wtyp, const systemtype_t styp, sint16 /*ok_sound*/)
301 {
302 // check if scenario forbids this
303 const waytype_t rwtyp = wtyp!=track_wt || styp!=type_tram ? wtyp : tram_wt;
304 if (!welt->get_scenario()->is_tool_allowed(welt->get_active_player(), TOOL_BUILD_WAY | GENERAL_TOOL, rwtyp)) {
305 return;
306 }
307
308 const uint16 time = welt->get_timeline_year_month();
309
310 // list of matching types (sorted by speed)
311 vector_tpl<const way_desc_t*> matching;
312
313 FOR(stringhashtable_tpl<way_desc_t const*>, const& i, desc_table) {
314 way_desc_t const* const desc = i.value;
315 if ( desc->get_styp()==styp && desc->get_wtyp()==wtyp && desc->get_builder() && desc->is_available(time) ) {
316 matching.append(desc);
317 }
318 }
319 std::sort(matching.begin(), matching.end(), compare_ways);
320
321 // now add sorted ways ...
322 FOR(vector_tpl<way_desc_t const*>, const i, matching) {
323 tool_selector->add_tool_selector(i->get_builder());
324 }
325 }
326
327
328 /* allow for railroad crossing
329 * @author prissi
330 */
check_crossing(const koord zv,const grund_t * bd,waytype_t wtyp0,const player_t * player) const331 bool way_builder_t::check_crossing(const koord zv, const grund_t *bd, waytype_t wtyp0, const player_t *player) const
332 {
333 const waytype_t wtyp = wtyp0==tram_wt ? track_wt : wtyp0;
334 // nothing to cross here
335 if (!bd->hat_wege()) {
336 return true;
337 }
338 // no triple crossings please
339 if (bd->has_two_ways() && !bd->hat_weg(wtyp)) {
340 return false;
341 }
342 const weg_t *w = bd->get_weg_nr(0);
343 // index of our wtype at the tile (must exists due to triple-crossing-check above)
344 const uint8 iwtyp = w->get_waytype() != wtyp;
345 // get the other way
346 if(iwtyp==0) {
347 w = bd->get_weg_nr(1);
348 // no other way here
349 if (w==NULL) {
350 return true;
351 }
352 }
353 // special case: tram track on road
354 if ( (wtyp==road_wt && w->get_waytype()==track_wt && w->get_desc()->get_styp()==type_tram) ||
355 (wtyp0==tram_wt && w->get_waytype()==road_wt) ) {
356 return true;
357 }
358 // right owner of the other way
359 if(!check_owner(w->get_owner(),player)) {
360 return false;
361 }
362 // check for existing crossing
363 crossing_t *cr = bd->find<crossing_t>();
364 if (cr) {
365 // index of the waytype in ns-direction at the crossing
366 const uint8 ns_way = cr->get_dir();
367 // only cross with the right direction
368 return (ns_way==iwtyp ? ribi_t::is_straight_ns(ribi_type(zv)) : ribi_t::is_straight_ew(ribi_type(zv)));
369 }
370 // no crossings in tunnels
371 if((bautyp & tunnel_flag)!=0 || bd->ist_tunnel()) {
372 return false;
373 }
374 // no crossings on elevated ways
375 if((bautyp & elevated_flag)!=0 || bd->get_typ()==grund_t::monorailboden) {
376 return false;
377 }
378 // crossing available and ribis ok
379 if(crossing_logic_t::get_crossing(wtyp, w->get_waytype(), 0, 0, welt->get_timeline_year_month())!=NULL) {
380 ribi_t::ribi w_ribi = w->get_ribi_unmasked();
381 // it is our way we want to cross: can we built a crossing here?
382 // both ways must be straight and no ends
383 return ribi_t::is_straight(w_ribi)
384 && !ribi_t::is_single(w_ribi)
385 && ribi_t::is_straight(ribi_type(zv))
386 && (w_ribi&ribi_type(zv))==0;
387 }
388 // cannot build crossing here
389 return false;
390 }
391
392
393 /* crossing of powerlines, or no powerline
394 * @author prissi
395 */
check_powerline(const koord zv,const grund_t * bd) const396 bool way_builder_t::check_powerline(const koord zv, const grund_t *bd) const
397 {
398 if(zv==koord(0,0)) {
399 return true;
400 }
401 leitung_t* lt = bd->find<leitung_t>();
402 if(lt!=NULL) {
403 ribi_t::ribi lt_ribi = lt->get_ribi();
404 // it is our way we want to cross: can we built a crossing here?
405 // both ways must be straight and no ends
406 return
407 ribi_t::is_straight(lt_ribi)
408 && !ribi_t::is_single(lt_ribi)
409 && ribi_t::is_straight(ribi_type(zv))
410 && (lt_ribi&ribi_type(zv))==0
411 && !bd->ist_tunnel();
412 }
413 // check for transformer
414 if (bd->find<pumpe_t>() != NULL || bd->find<senke_t>() != NULL) {
415 return false;
416 }
417 // ok, there is not high power transmission stuff going on here
418 return true;
419 }
420
421
422 // allowed slope?
check_slope(const grund_t * from,const grund_t * to)423 bool way_builder_t::check_slope( const grund_t *from, const grund_t *to )
424 {
425 const koord from_pos=from->get_pos().get_2d();
426 const koord to_pos=to->get_pos().get_2d();
427 const koord zv=to_pos-from_pos;
428
429 if( !desc->has_double_slopes()
430 && ( (from->get_weg_hang() && !(from->get_weg_hang() & 7))
431 || (to->get_weg_hang() && !(to->get_weg_hang() & 7)) ) ) {
432 return false;
433 }
434
435 if(from==to) {
436 if(!slope_t::is_way(from->get_weg_hang())) {
437 return false;
438 }
439 }
440 else {
441 if(from->get_weg_hang() && ribi_t::doubles(ribi_type(from->get_weg_hang()))!=ribi_t::doubles(ribi_type(zv))) {
442 return false;
443 }
444 if(to->get_weg_hang() && ribi_t::doubles(ribi_type(to->get_weg_hang()))!=ribi_t::doubles(ribi_type(zv))) {
445 return false;
446 }
447 }
448
449 return true;
450 }
451
452
453 // allowed owner?
check_owner(const player_t * player1,const player_t * player2) const454 bool way_builder_t::check_owner( const player_t *player1, const player_t *player2 ) const
455 {
456 // unowned, mine or public property or superuser ... ?
457 return player1==NULL || player1==player2 || player1==welt->get_public_player() || player2==welt->get_public_player();
458 }
459
460
461 /* do not go through depots, station buildings etc. ...
462 * direction results from layout
463 */
check_building(const grund_t * to,const koord dir) const464 bool way_builder_t::check_building( const grund_t *to, const koord dir ) const
465 {
466 if(dir==koord(0,0)) {
467 return true;
468 }
469 if(to->obj_count()<=0) {
470 return true;
471 }
472
473 // first find all kind of buildings
474 gebaeude_t *gb = to->find<gebaeude_t>();
475 if(gb==NULL) {
476 // but depots might be overlooked ...
477 depot_t* depot = to->get_depot();
478 // no road to tram depot and vice-versa
479 if (depot) {
480 if ( (waytype_t)(bautyp&bautyp_mask) != depot->get_waytype() ) {
481 return false;
482 }
483 }
484 gb = depot;
485 }
486 // check, if we may enter
487 if(gb) {
488 // now check for directions
489 uint8 layouts = gb->get_tile()->get_desc()->get_all_layouts();
490 uint8 layout = gb->get_tile()->get_layout();
491 ribi_t::ribi r = ribi_type(dir);
492 if( layouts&1 ) {
493 return false;
494 }
495 if( layouts==4 ) {
496 return r == ribi_t::layout_to_ribi[layout];
497 }
498 return ribi_t::is_straight( r | ribi_t::doubles(ribi_t::layout_to_ribi[layout&1]) );
499 }
500 return true;
501 }
502
503
504 /* This is the core routine for the way search
505 * it will check
506 * A) allowed step
507 * B) if allowed, calculate the cost for the step from from to to
508 * @author prissi
509 */
is_allowed_step(const grund_t * from,const grund_t * to,sint32 * costs,bool is_upperlayer) const510 bool way_builder_t::is_allowed_step(const grund_t *from, const grund_t *to, sint32 *costs, bool is_upperlayer ) const
511 {
512 const koord from_pos=from->get_pos().get_2d();
513 const koord to_pos=to->get_pos().get_2d();
514 const koord zv=to_pos-from_pos;
515 // fake empty elevated tiles
516 static monorailboden_t to_dummy(koord3d::invalid, slope_t::flat);
517 static monorailboden_t from_dummy(koord3d::invalid, slope_t::flat);
518
519 if(bautyp==luft && (from->get_grund_hang()+to->get_grund_hang()!=0 || (from->hat_wege() && from->hat_weg(air_wt)==0) || (to->hat_wege() && to->hat_weg(air_wt)==0))) {
520 // absolutely no slopes for runways, neither other ways
521 return false;
522 }
523
524 bool to_flat = false; // to tile will be flattened
525 if(from==to) {
526 if((bautyp&tunnel_flag) && !slope_t::is_way(from->get_weg_hang())) {
527 return false;
528 }
529 }
530 else {
531 // check slopes
532 bool ok_slope = from->get_weg_hang() == slope_t::flat || ribi_t::doubles(ribi_type(from->get_weg_hang()))==ribi_t::doubles(ribi_type(zv));
533 ok_slope &= to->get_weg_hang() == slope_t::flat || ribi_t::doubles(ribi_type(to->get_weg_hang()))==ribi_t::doubles(ribi_type(zv));
534
535 // try terraforming
536 if (!ok_slope) {
537 uint8 dummy,to_slope;
538 if ( (bautyp & terraform_flag) != 0 && from->ist_natur() && to->ist_natur() && check_terraforming(from,to,&dummy,&to_slope) ) {
539 to_flat = to_slope == slope_t::flat;
540 }
541 else {
542 // slopes not ok and no terraforming possible
543 return false;
544 }
545 }
546 }
547
548 // ok, slopes are ok
549 bool ok = true;
550
551 // check scenario conditions
552 if (welt->get_scenario()->is_work_allowed_here(player_builder, (bautyp&tunnel_flag ? TOOL_BUILD_TUNNEL : TOOL_BUILD_WAY)|GENERAL_TOOL, bautyp&bautyp_mask, to->get_pos()) != NULL) {
553 return false;
554 }
555
556 // universal check for elevated things ...
557 if(bautyp&elevated_flag) {
558 if( is_upperlayer ) {
559 if( (to->get_typ() != grund_t::monorailboden || to->get_weg_nr(0)->get_desc()->get_wtyp()!=desc->get_wtyp() || !check_owner(to->obj_bei(0)->get_owner(),player_builder) ) || (from->get_typ() != grund_t::monorailboden || from->get_weg_nr(0)->get_desc()->get_wtyp()!=desc->get_wtyp() || !check_owner(from->obj_bei(0)->get_owner(),player_builder) ) ) {
560 return false;
561 }
562 }
563 else {
564 if( to->hat_weg(air_wt) || welt->lookup_hgt( to_pos ) < welt->get_water_hgt( to_pos ) || !check_powerline( zv, to ) || (!to->ist_karten_boden() && to->get_typ() != grund_t::monorailboden) || to->get_typ() == grund_t::brueckenboden || to->get_typ() == grund_t::tunnelboden ) {
565 // no suitable ground below!
566 return false;
567 }
568 gebaeude_t *gb = to->find<gebaeude_t>();
569 if(gb==NULL) {
570 // but depots might be overlooked ...
571 gb = to->get_depot();
572 }
573 if(gb) {
574 // no halt => citybuilding => do not touch
575 // also check for too high buildings ...
576 if(!check_owner(gb->get_owner(),player_builder) || gb->get_tile()->get_background(0,1,0)!=IMG_EMPTY) {
577 return false;
578 }
579 // building above houses is expensive ... avoid it!
580 *costs += 4;
581 }
582 // absolutely nothing allowed here for set which want double clearance
583 if( welt->get_settings().get_way_height_clearance()==2 && welt->lookup( to->get_pos()+koord3d(0,0,1) ) ) {
584 return false;
585 }
586 // up to now 'to' and 'from' referred to the ground one height step below the elevated way
587 // now get the grounds at the right height
588 koord3d pos = to->get_pos() + koord3d( 0, 0, welt->get_settings().get_way_height_clearance() );
589 grund_t *to2 = welt->lookup(pos);
590 if(to2) {
591 if(to2->get_weg_nr(0)) {
592 // already an elevated ground here => it will have always a way object, that indicates ownership
593 ok = to2->get_typ()==grund_t::monorailboden && check_owner(to2->obj_bei(0)->get_owner(),player_builder);
594 ok &= to2->get_weg_nr(0)->get_desc()->get_wtyp()==desc->get_wtyp();
595 }
596 else {
597 ok = to2->find<leitung_t>()==NULL;
598 }
599 if (!ok) {
600 return false;
601 }
602 to = to2;
603 }
604 else {
605 // simulate empty elevated tile
606 to_dummy.set_pos(pos);
607 to_dummy.set_grund_hang(to->get_grund_hang());
608 to = &to_dummy;
609 }
610
611 pos = from->get_pos() + koord3d( 0, 0, env_t::pak_height_conversion_factor );
612 grund_t *from2 = welt->lookup(pos);
613 if(from2) {
614 from = from2;
615 }
616 else {
617 // simulate empty elevated tile
618 from_dummy.set_pos(pos);
619 from_dummy.set_grund_hang(from->get_grund_hang());
620 from = &from_dummy;
621 }
622 // now 'from' and 'to' point to grounds at the right height
623 }
624 }
625
626 if( welt->get_settings().get_way_height_clearance()==2 ) {
627 // cannot build if conversion factor 2, we aren't powerline and way with maximum speed > 0 or powerline 1 tile below
628 grund_t *to2 = welt->lookup( to->get_pos() + koord3d(0, 0, -1) );
629 if( to2 && (((bautyp&bautyp_mask)!=leitung && to2->get_weg_nr(0) && to2->get_weg_nr(0)->get_desc()->get_topspeed()>0) || to2->get_leitung()) ) {
630 return false;
631 }
632 // tile above cannot have way unless we are a way (not powerline) with a maximum speed of 0, or be surface if we are underground
633 to2 = welt->lookup( to->get_pos() + koord3d(0, 0, 1) );
634 if( to2 && ((to2->get_weg_nr(0) && (desc->get_topspeed()>0 || (bautyp&bautyp_mask)==leitung)) || (bautyp & tunnel_flag) != 0) ) {
635 return false;
636 }
637 }
638
639 // universal check for depots/stops/...
640 if( !check_building( from, zv ) || !check_building( to, -zv ) ) {
641 return false;
642 }
643
644 // universal check for bridges: enter bridges in bridge direction
645 if( to->get_typ()==grund_t::brueckenboden ) {
646 ribi_t::ribi br = ribi_type(zv);
647 br = to->hat_wege() ? to->get_weg_nr(0)->get_ribi_unmasked() : (ribi_t::ribi)ribi_t::none;
648 br |= to->get_leitung() ? to->get_leitung()->get_ribi() : (ribi_t::ribi)ribi_t::none;
649 if(!ribi_t::is_straight(br)) {
650 return false;
651 }
652 }
653 if( from->get_typ()==grund_t::brueckenboden ) {
654 ribi_t::ribi br = ribi_type(zv);
655 br = from->hat_wege() ? from->get_weg_nr(0)->get_ribi_unmasked() : (ribi_t::ribi)ribi_t::none;
656 br |= from->get_leitung() ? from->get_leitung()->get_ribi() : (ribi_t::ribi)ribi_t::none;
657 if(!ribi_t::is_straight(br)) {
658 return false;
659 }
660 }
661
662 // universal check: do not switch to tunnel through cliffs!
663 if( from->get_typ() == grund_t::tunnelboden && to->get_typ() != grund_t::tunnelboden && !from->ist_karten_boden() ) {
664 return false;
665 }
666 if( to->get_typ()==grund_t::tunnelboden && from->get_typ() != grund_t::tunnelboden && !to->ist_karten_boden() ) {
667 return false;
668 }
669
670 // universal check for crossings
671 if (to!=from && (bautyp&bautyp_mask)!=leitung) {
672 waytype_t const wtyp = (bautyp == river) ? water_wt : (waytype_t)(bautyp & bautyp_mask);
673 if(!check_crossing(zv,to,wtyp,player_builder) || !check_crossing(-zv,from,wtyp,player_builder)) {
674 return false;
675 }
676 }
677
678 // universal check for building under powerlines
679 if ((bautyp&bautyp_mask)!=leitung) {
680 if (!check_powerline(zv,to) || !check_powerline(-zv,from)) {
681 return false;
682 }
683 }
684
685 bool fundament = to->get_typ()==grund_t::fundament;
686
687 // now check way specific stuff
688 settings_t const& s = welt->get_settings();
689 switch(bautyp&bautyp_mask) {
690
691 case strasse:
692 {
693 const weg_t *str=to->get_weg(road_wt);
694
695 // we allow connection to any road
696 ok = (str || !fundament) && !to->is_water();
697 if(!ok) {
698 return false;
699 }
700 // check for end/start of bridge or tunnel
701 // fail if no proper way exists, or the way's ribi are not 0 and are not matching the slope type
702 ribi_t::ribi test_ribi = (str ? str->get_ribi_unmasked() : 0) | ribi_type(zv);
703 if(to->get_weg_hang()!=to->get_grund_hang() && (str==NULL || !(ribi_t::is_straight(test_ribi) || test_ribi==0 ))) {
704 return false;
705 }
706 // calculate costs
707 *costs = str ? 0 : s.way_count_straight;
708 if((str==NULL && to->hat_wege()) || (str && to->has_two_ways())) {
709 *costs += 4; // avoid crossings
710 }
711 if(to->get_weg_hang()!=0 && !to_flat) {
712 *costs += s.way_count_slope;
713 }
714 }
715 break;
716
717 case schiene:
718 default:
719 {
720 const weg_t *sch=to->get_weg(desc->get_wtyp());
721 // extra check for AI construction (not adding to existing tracks!)
722 if((bautyp&bot_flag)!=0 && (sch || to->get_halt().is_bound())) {
723 return false;
724 }
725 // ok, regular construction here
726 // if no way there: check for right ground type, otherwise check owner
727 ok = sch==NULL ? (!fundament && !to->is_water()) : check_owner(sch->get_owner(),player_builder);
728 if(!ok) {
729 return false;
730 }
731 // check for end/start of bridge or tunnel
732 // fail if no proper way exists, or the way's ribi are not 0 and are not matching the slope type
733 ribi_t::ribi test_ribi = (sch ? sch->get_ribi_unmasked() : 0) | ribi_type(zv);
734 if(to->get_weg_hang()!=to->get_grund_hang() && (sch==NULL || !(ribi_t::is_straight(test_ribi) || test_ribi==0 ))) {
735 return false;
736 }
737 // calculate costs
738 *costs = s.way_count_straight;
739 if (!sch) *costs += 1; // only prefer existing rails a little
740 if((sch && to->has_two_ways()) || (sch==NULL && to->hat_wege())) {
741 *costs += 4; // avoid crossings
742 }
743 if(to->get_weg_hang()!=0 && !to_flat) {
744 *costs += s.way_count_slope;
745 }
746 }
747 break;
748
749 case schiene_tram: // Dario: Tramway
750 {
751 const weg_t *sch=to->get_weg(track_wt);
752 // roads are checked in check_crossing
753 // if no way there: check for right ground type, otherwise check owner
754 ok = sch==NULL ? (!fundament && !to->is_water()) : check_owner(sch->get_owner(),player_builder);
755 // tram track allowed in road tunnels, but only along existing roads / tracks
756 if(from!=to) {
757 if(from->ist_tunnel()) {
758 const ribi_t::ribi ribi = from->get_weg_ribi_unmasked(road_wt) | from->get_weg_ribi_unmasked(track_wt) | ribi_t::doubles(ribi_type(from->get_grund_hang()));
759 ok = ok && ((ribi & ribi_type(zv))==ribi_type(zv));
760 }
761 if(to->ist_tunnel()) {
762 const ribi_t::ribi ribi = to->get_weg_ribi_unmasked(road_wt) | to->get_weg_ribi_unmasked(track_wt) | ribi_t::doubles(ribi_type(to->get_grund_hang()));
763 ok = ok && ((ribi & ribi_type(-zv))==ribi_type(-zv));
764 }
765 }
766 if(ok) {
767 // calculate costs
768 *costs = s.way_count_straight;
769 if (!to->hat_weg(track_wt)) *costs += 1; // only prefer existing rails a little
770 // prefer own track
771 if(to->hat_weg(road_wt)) {
772 *costs += s.way_count_straight;
773 }
774 if(to->get_weg_hang()!=0 && !to_flat) {
775 *costs += s.way_count_slope;
776 }
777 }
778 }
779 break;
780
781 case leitung:
782 ok = !to->is_water() && (to->get_weg(air_wt)==NULL);
783 ok &= !(to->ist_tunnel() && to->hat_wege());
784 if(to->get_weg_nr(0)!=NULL) {
785 // only 90 deg crossings, only a single way
786 ribi_t::ribi w_ribi= to->get_weg_nr(0)->get_ribi_unmasked();
787 ok &= ribi_t::is_straight(w_ribi) && !ribi_t::is_single(w_ribi) && ribi_t::is_straight(ribi_type(zv)) && (w_ribi&ribi_type(zv))==0;
788 }
789 if(to->has_two_ways()) {
790 // only 90 deg crossings, only for trams ...
791 ribi_t::ribi w_ribi= to->get_weg_nr(1)->get_ribi_unmasked();
792 ok &= ribi_t::is_straight(w_ribi) && !ribi_t::is_single(w_ribi) && ribi_t::is_straight(ribi_type(zv)) && (w_ribi&ribi_type(zv))==0;
793 }
794 // do not connect to other powerlines
795 {
796 leitung_t *lt = to->get_leitung();
797 ok &= (lt==NULL) || check_owner(player_builder, lt->get_owner());
798 }
799
800 if(to->get_typ()!=grund_t::tunnelboden) {
801 // only fields are allowed
802 if(to->get_typ()==grund_t::fundament) {
803 ok &= to->find<field_t>()!=NULL;
804 }
805 // no bridges and monorails here in the air
806 ok &= (welt->access(to_pos)->get_boden_in_hoehe(to->get_pos().z+1)==NULL);
807 }
808
809 // calculate costs
810 if(ok) {
811 *costs = s.way_count_straight;
812 if( !to->get_leitung() ) {
813 // extra malus for not following an existing line or going on ways
814 *costs += s.way_count_double_curve + (to->hat_wege() ? 8 : 0); // prefer existing powerlines
815 }
816 }
817 break;
818
819 case wasser:
820 {
821 const weg_t *canal = to->get_weg(water_wt);
822 // if no way there: check for right ground type, otherwise check owner
823 ok = canal || !fundament;
824 // calculate costs
825 if(ok) {
826 *costs = to->is_water() || canal ? s.way_count_straight : s.way_count_leaving_road; // prefer water very much
827 if(to->get_weg_hang()!=0 && !to_flat) {
828 *costs += s.way_count_slope * 2;
829 }
830 }
831 break;
832 }
833
834 case river:
835 if( to->is_water() ) {
836 ok = true;
837 // do not care while in ocean
838 *costs = 1;
839 }
840 else {
841 // only downstream
842 ok = from->get_pos().z>=to->get_pos().z && (to->hat_weg(water_wt) || !to->hat_wege());
843 // calculate costs
844 if(ok) {
845 // prefer existing rivers:
846 *costs = to->hat_weg(water_wt) ? 10 : 10+simrand(s.way_count_90_curve);
847 if(to->get_weg_hang()!=0 && !to_flat) {
848 *costs += s.way_count_slope * 10;
849 }
850 }
851 }
852 break;
853
854 case luft: // hsiegeln: runway
855 {
856 const weg_t *w = to->get_weg(air_wt);
857 if( w && w->get_desc()->get_styp()==type_runway && desc->get_styp()!=type_runway && ribi_t::is_single(w->get_ribi_unmasked()) ) {
858 // cannot go over the end of a runway with a taxiway
859 return false;
860 }
861 ok = !to->is_water() && (w || !to->hat_wege()) && to->find<leitung_t>()==NULL && !fundament;
862 // calculate costs
863 *costs = s.way_count_straight;
864 }
865 break;
866 }
867 return ok;
868 }
869
check_terraforming(const grund_t * from,const grund_t * to,uint8 * new_from_slope,uint8 * new_to_slope) const870 bool way_builder_t::check_terraforming( const grund_t *from, const grund_t *to, uint8* new_from_slope, uint8* new_to_slope) const
871 {
872 // only for normal green tiles
873 const slope_t::type from_slope = from->get_weg_hang();
874 const slope_t::type to_slope = to->get_weg_hang();
875 const sint8 from_hgt = from->get_hoehe();
876 const sint8 to_hgt = to->get_hoehe();
877 // we may change slope of a tile if it is sloped already
878 if( (from_slope == slope_t::flat || from->get_hoehe() == welt->get_water_hgt( from->get_pos().get_2d() ))
879 && (to_slope == slope_t::flat || to->get_hoehe() == welt->get_water_hgt( to->get_pos().get_2d() )) ) {
880 return false;
881 }
882 else if( abs( from_hgt - to_hgt ) <= (desc->has_double_slopes() ? 2 : 1) ) {
883 // extra check for double heights
884 if( abs( from_hgt - to_hgt) == 2 && (welt->lookup( from->get_pos() - koord3d(0,0,2) ) != NULL || welt->lookup( from->get_pos() + koord3d(0, 0, 2) ) != NULL
885 || welt->lookup( to->get_pos() - koord3d(0, 0, 2) ) != NULL || welt->lookup( to->get_pos() + koord3d(0, 0, 2) ) != NULL) ) {
886 return false;
887 }
888 // monorail above / tunnel below
889 if (welt->lookup(from->get_pos() - koord3d(0,0,1))!=NULL || welt->lookup(from->get_pos() + koord3d(0,0,1))!=NULL
890 || welt->lookup(to->get_pos() - koord3d(0,0,1))!=NULL || welt->lookup(to->get_pos() + koord3d(0,0,1))!=NULL) {
891 return false;
892 }
893 // can safely change slope of at least one of the tiles
894 if (new_from_slope == NULL) {
895 return true;
896 }
897 // now calculate new slopes
898 assert(new_from_slope);
899 assert(new_to_slope);
900 // direction of way
901 const koord dir = (to->get_pos() - from->get_pos()).get_2d();
902 sint8 start = from_hgt * 2;
903 sint8 middle = from_hgt * 2;
904 sint8 end = to_hgt * 2;
905 // get 3 heights - start (min start from, but should be same), middle (average end from/average start to), end (min end to)
906 if( dir == koord::north ) {
907 start += corner_sw(from_slope) + corner_se(from_slope);
908 middle += corner_ne(from_slope) + corner_nw(from_slope);
909 end += corner_ne(to_slope) + corner_nw(to_slope);
910 }
911 else if( dir == koord::east ) {
912 start += corner_sw(from_slope) + corner_nw(from_slope);
913 middle += corner_se(from_slope) + corner_ne(from_slope);
914 end += corner_se(to_slope) + corner_ne(to_slope);
915 }
916 else if( dir == koord::south ) {
917 start += corner_ne(from_slope) + corner_nw(from_slope);
918 middle += corner_sw(from_slope) + corner_se(from_slope);
919 end += corner_sw(to_slope) + corner_se(to_slope);
920 }
921 else if( dir == koord::west ) {
922 start += corner_se(from_slope) + corner_ne(from_slope);
923 middle += corner_sw(from_slope) + corner_nw(from_slope);
924 end += corner_sw(to_slope) + corner_nw(to_slope);
925 }
926 // work out intermediate height:
927 if( end == start ) {
928 middle = start;
929 }
930 else {
931 // end < start to ist wegbar?assert from ist_wegbar:middle = end + 1
932 // end > start to ist wegbar?assert from ist_wegbar:middle = end - 1
933 if( !slope_t::is_way( to_slope ) ) {
934 middle = (start + end) / 2;
935 }
936 }
937 // prevent middle being invalid
938 if( middle >> 1 > from_hgt + 2 ) {
939 middle = (from_hgt + 2) * 2;
940 }
941 if( middle >> 1 > to_hgt + 2 ) {
942 middle = (to_hgt + 2) * 2;
943 }
944 if( middle >> 1 < from_hgt ) {
945 middle = from_hgt * 2;
946 }
947 if( middle >> 1 < to_hgt ) {
948 middle = to_hgt * 2;
949 }
950 const uint8 m_from = (middle >> 1) - from_hgt;
951 const uint8 m_to = (middle >> 1) - to_hgt;
952
953 // write middle heights
954 if( dir == koord::north ) {
955 *new_from_slope = corner_sw(from_slope) + corner_se(from_slope) * 3 + m_from * 9 + m_from * 27;
956 *new_to_slope = m_to + m_to * 3 + corner_ne(to_slope) * 9 + corner_nw(to_slope) * 27;
957 }
958 else if( dir == koord::east ) {
959 *new_from_slope = corner_sw(from_slope) + m_from * 3 + m_from * 9 + corner_nw(from_slope) * 27;
960 *new_to_slope = m_to + corner_se(to_slope) * 3 + corner_ne(to_slope) * 9 + m_to * 27;
961 }
962 else if( dir == koord::south ) {
963 *new_from_slope = m_from + m_from * 3 + corner_ne(from_slope) * 9 + corner_nw(from_slope) * 27;
964 *new_to_slope = corner_sw(to_slope) + corner_se(to_slope) * 3 + m_to * 9 + m_to * 27;
965 }
966 else if( dir == koord::west ) {
967 *new_from_slope = m_from + corner_se(from_slope) * 3 + corner_ne(from_slope) * 9 + m_from * 27;
968 *new_to_slope = corner_sw(to_slope) + m_to * 3 + m_to * 9 + corner_nw(to_slope) * 27;
969 }
970 return true;
971 }
972 return false;
973 }
974
do_terraforming()975 void way_builder_t::do_terraforming()
976 {
977 uint32 last_terraformed = terraform_index.get_count();
978
979 FOR(vector_tpl<uint32>, const i, terraform_index) { // index in route
980 grund_t *from = welt->lookup(route[i]);
981 uint8 from_slope = from->get_grund_hang();
982
983 grund_t *to = welt->lookup(route[i+1]);
984 uint8 to_slope = to->get_grund_hang();
985 // calculate new slopes
986 check_terraforming(from, to, &from_slope, &to_slope);
987 bool changed = false;
988 // change slope of from
989 if( from_slope != from->get_grund_hang() ) {
990 if( from_slope == slope_t::raised ) {
991 from->set_hoehe( from->get_hoehe() + 2 );
992 from->set_grund_hang( slope_t::flat );
993 route[i].z = from->get_hoehe();
994 }
995 else if( from_slope != slope_t::raised / 2 ) {
996 // bit of a hack to recognise single height slopes shifted up 1
997 if( from_slope > slope_t::raised / 2 && slope_t::is_single( from_slope-slope_t::raised / 2 ) ) {
998 from->set_hoehe( from->get_hoehe() + 1 );
999 from_slope -= slope_t::raised / 2;
1000 route[i].z = from->get_hoehe();
1001 }
1002 from->set_grund_hang( from_slope );
1003 }
1004 else {
1005 from->set_hoehe( from->get_hoehe() + 1 );
1006 from->set_grund_hang( slope_t::flat );
1007 route[i].z = from->get_hoehe();
1008 }
1009 changed = true;
1010 if (last_terraformed != i) {
1011 // charge player
1012 player_t::book_construction_costs(player_builder, welt->get_settings().cst_set_slope, from->get_pos().get_2d(), ignore_wt);
1013 }
1014 }
1015 // change slope of to
1016 if( to_slope != to->get_grund_hang() ) {
1017 if( to_slope == slope_t::raised ) {
1018 to->set_hoehe( to->get_hoehe() + 2 );
1019 to->set_grund_hang( slope_t::flat );
1020 route[i + 1].z = to->get_hoehe();
1021 }
1022 else if( to_slope != slope_t::raised / 2 ) {
1023 // bit of a hack to recognise single height slopes shifted up 1
1024 if( to_slope > slope_t::raised / 2 && slope_t::is_single( to_slope-slope_t::raised / 2 ) ) {
1025 to->set_hoehe( to->get_hoehe() + 1 );
1026 to_slope -= slope_t::raised / 2;
1027 route[i + 1].z = to->get_hoehe();
1028 }
1029 to->set_grund_hang(to_slope);
1030 }
1031 else {
1032 to->set_hoehe( to->get_hoehe() + 1);
1033 to->set_grund_hang(slope_t::flat);
1034 route[i+1].z = to->get_hoehe();
1035 }
1036 changed = true;
1037 // charge player
1038 player_t::book_construction_costs(player_builder, welt->get_settings().cst_set_slope, to->get_pos().get_2d(), ignore_wt);
1039 last_terraformed = i+1; // do not pay twice for terraforming one tile
1040 }
1041 // recalc slope image of neighbors
1042 if (changed) {
1043 for(uint8 j=0; j<2; j++) {
1044 for(uint8 x=0; x<2; x++) {
1045 for(uint8 y=0; y<2; y++) {
1046 grund_t *gr = welt->lookup_kartenboden(route[i+j].get_2d()+koord(x,y));
1047 if (gr) {
1048 gr->calc_image();
1049 }
1050 }
1051 }
1052 }
1053 }
1054 }
1055 }
1056
check_for_bridge(const grund_t * parent_from,const grund_t * from,const vector_tpl<koord3d> & ziel)1057 void way_builder_t::check_for_bridge(const grund_t* parent_from, const grund_t* from, const vector_tpl<koord3d> &ziel)
1058 {
1059 // wrong starting slope or tile already occupied with a way ...
1060 if (!slope_t::is_way(from->get_grund_hang())) {
1061 return;
1062 }
1063
1064 /*
1065 * now check existing ways:
1066 * no tunnels/bridges at crossings and no track tunnels/bridges on roads (but road tunnels/bridges on tram are allowed).
1067 * (keep in mind, that our waytype isn't currently on the tile and will be built later)
1068 */
1069 const weg_t *way0 = from->get_weg_nr(0);
1070 const weg_t *way1 = from->get_weg_nr(1);
1071 if( way0 ) {
1072 switch( bautyp&bautyp_mask ) {
1073 case schiene_tram:
1074 case strasse: {
1075 const weg_t *other = way1;
1076 if ( way0->get_waytype() != desc->get_wtyp() ) {
1077 if ( way1 ) {
1078 // two different ways
1079 return;
1080 }
1081 other = way0;
1082 }
1083 if ( other ) {
1084 if ( (bautyp&bautyp_mask) == strasse ) {
1085 if ( other->get_waytype() != track_wt || other->get_desc()->get_styp()!=type_tram ) {
1086 // road only on tram
1087 return;
1088 }
1089 }
1090 else {
1091 if ( other->get_waytype() != road_wt ) {
1092 // tram only on road
1093 return;
1094 }
1095 }
1096 }
1097 }
1098 /* FALLTHROUGH */
1099
1100 default:
1101 if (way0->get_waytype()!=desc->get_wtyp() || way1!=NULL) {
1102 // no other ways allowed
1103 return;
1104 }
1105 }
1106 }
1107
1108 const koord zv=from->get_pos().get_2d()-parent_from->get_pos().get_2d();
1109 const ribi_t::ribi ribi = ribi_type(zv);
1110
1111 // now check ribis of existing ways
1112 const ribi_t::ribi wayribi = way0 ? way0->get_ribi_unmasked() | (way1 ? way1->get_ribi_unmasked() : (ribi_t::ribi)ribi_t::none) : (ribi_t::ribi)ribi_t::none;
1113 if ( wayribi & (~ribi) ) {
1114 // curves at bridge start
1115 return;
1116 }
1117
1118 // ok, so now we do a closer investigation
1119 if( bridge_desc && ( ribi_type(from->get_grund_hang()) == ribi_t::backward(ribi_type(zv)) || from->get_grund_hang() == 0 )
1120 && bridge_builder_t::can_place_ramp(player_builder, from, desc->get_wtyp(),ribi_t::backward(ribi_type(zv))) ) {
1121 // Try a bridge.
1122 const sint32 cost_difference = desc->get_maintenance() > 0 ? (bridge_desc->get_maintenance() * 4l + 3l) / desc->get_maintenance() : 16;
1123 // try eight possible lengths ..
1124 uint32 min_length = 1;
1125 for (uint8 i = 0; i < 8 && min_length <= welt->get_settings().way_max_bridge_len; ++i) {
1126 sint8 bridge_height;
1127 const char *error = NULL;
1128 koord3d end = bridge_builder_t::find_end_pos( player_builder, from->get_pos(), zv, bridge_desc, error, bridge_height, true, min_length );
1129 const grund_t* gr_end = welt->lookup(end);
1130 if( gr_end == NULL) {
1131 // no valid end point found
1132 min_length++;
1133 continue;
1134 }
1135 uint32 length = koord_distance(from->get_pos(), end);
1136 if(!ziel.is_contained(end) && bridge_builder_t::can_place_ramp(player_builder, gr_end, desc->get_wtyp(), ribi_type(zv))) {
1137 // If there is a slope on the starting tile, it's taken into account in is_allowed_step, but a bridge will be flat!
1138 sint8 num_slopes = (from->get_grund_hang() == slope_t::flat) ? 1 : -1;
1139 // On the end tile, we haven't to subtract way_count_slope, since is_allowed_step isn't called with this tile.
1140 num_slopes += (gr_end->get_grund_hang() == slope_t::flat) ? 1 : 0;
1141 next_gr.append(next_gr_t(welt->lookup(end), length * cost_difference + num_slopes*welt->get_settings().way_count_slope, build_straight | build_tunnel_bridge));
1142 min_length = length+1;
1143 }
1144 else {
1145 break;
1146 }
1147 }
1148 return;
1149 }
1150
1151 if( tunnel_desc && ribi_type(from->get_grund_hang()) == ribi_type(zv) ) {
1152 // uphill hang ... may be tunnel?
1153 const sint32 cost_difference = desc->get_maintenance() > 0 ? (tunnel_desc->get_maintenance() * 4l + 3l) / desc->get_maintenance() : 16;
1154 koord3d end = tunnel_builder_t::find_end_pos( player_builder, from->get_pos(), zv, tunnel_desc);
1155 if( end != koord3d::invalid && !ziel.is_contained(end) ) {
1156 uint32 length = koord_distance(from->get_pos(), end);
1157 next_gr.append(next_gr_t(welt->lookup(end), length * cost_difference, build_straight | build_tunnel_bridge ));
1158 return;
1159 }
1160 }
1161 }
1162
1163
way_builder_t(player_t * player)1164 way_builder_t::way_builder_t(player_t* player) : next_gr(32)
1165 {
1166 player_builder = player;
1167 bautyp = strasse; // kann mit init_builder() gesetzt werden
1168 maximum = 2000;// CA $ PER TILE
1169
1170 keep_existing_ways = false;
1171 keep_existing_city_roads = false;
1172 keep_existing_faster_ways = false;
1173 build_sidewalk = false;
1174 }
1175
1176
1177 /**
1178 * If a way is built on top of another way, should the type
1179 * of the former way be kept or replaced (true == keep)
1180 * @author Hj. Malthaner
1181 */
set_keep_existing_ways(bool yesno)1182 void way_builder_t::set_keep_existing_ways(bool yesno)
1183 {
1184 keep_existing_ways = yesno;
1185 keep_existing_faster_ways = false;
1186 }
1187
1188
set_keep_existing_faster_ways(bool yesno)1189 void way_builder_t::set_keep_existing_faster_ways(bool yesno)
1190 {
1191 keep_existing_ways = false;
1192 keep_existing_faster_ways = yesno;
1193 }
1194
1195
init_builder(bautyp_t wt,const way_desc_t * b,const tunnel_desc_t * tunnel,const bridge_desc_t * br)1196 void way_builder_t::init_builder(bautyp_t wt, const way_desc_t *b, const tunnel_desc_t *tunnel, const bridge_desc_t *br)
1197 {
1198 bautyp = wt;
1199 desc = b;
1200 bridge_desc = br;
1201 tunnel_desc = tunnel;
1202 if(wt&tunnel_flag && tunnel==NULL) {
1203 dbg->fatal("way_builder_t::init_builder()","needs a tunnel description for an underground route!");
1204 }
1205 if((wt&bautyp_mask)==luft) {
1206 wt &= bautyp_mask | bot_flag;
1207 }
1208 if(player_builder==NULL) {
1209 bridge_desc = NULL;
1210 tunnel_desc = NULL;
1211 }
1212 else if( bautyp != river ) {
1213 #ifdef AUTOMATIC_BRIDGES
1214 if( bridge_desc == NULL ) {
1215 bridge_desc = bridge_builder_t::find_bridge(b->get_wtyp(), 25, welt->get_timeline_year_month());
1216 }
1217 #endif
1218 #ifdef AUTOMATIC_TUNNELS
1219 if( tunnel_desc == NULL ) {
1220 tunnel_desc = tunnel_builder_t::get_tunnel_desc(b->get_wtyp(), 25, welt->get_timeline_year_month());
1221 }
1222 #endif
1223 }
1224 DBG_MESSAGE("way_builder_t::init_builder()",
1225 "setting way type to %d, desc=%s, bridge_desc=%s, tunnel_desc=%s",
1226 bautyp,
1227 desc ? desc->get_name() : "NULL",
1228 bridge_desc ? bridge_desc->get_name() : "NULL",
1229 tunnel_desc ? tunnel_desc->get_name() : "NULL"
1230 );
1231 }
1232
1233
get_mini_maxi(const vector_tpl<koord3d> & ziel,koord3d & mini,koord3d & maxi)1234 void get_mini_maxi( const vector_tpl<koord3d> &ziel, koord3d &mini, koord3d &maxi )
1235 {
1236 mini = maxi = ziel[0];
1237 FOR(vector_tpl<koord3d>, const& current, ziel) {
1238 if( current.x < mini.x ) {
1239 mini.x = current.x;
1240 } else if( current.x > maxi.x ) {
1241 maxi.x = current.x;
1242 }
1243 if( current.y < mini.y ) {
1244 mini.y = current.y;
1245 } else if( current.y > maxi.y ) {
1246 maxi.y = current.y;
1247 }
1248 if( current.z < mini.z ) {
1249 mini.z = current.z;
1250 } else if( current.z > maxi.z ) {
1251 maxi.z = current.z;
1252 }
1253 }
1254 }
1255
1256
1257 /* this routine uses A* to calculate the best route
1258 * beware: change the cost and you will mess up the system!
1259 * (but you can try, look at simuconf.tab)
1260 */
intern_calc_route(const vector_tpl<koord3d> & start,const vector_tpl<koord3d> & ziel)1261 sint32 way_builder_t::intern_calc_route(const vector_tpl<koord3d> &start, const vector_tpl<koord3d> &ziel)
1262 {
1263 // we clear it here probably twice: does not hurt ...
1264 route.clear();
1265 terraform_index.clear();
1266
1267 // check for existing koordinates
1268 bool has_target_ground = false;
1269 FOR(vector_tpl<koord3d>, const& i, ziel) {
1270 has_target_ground |= welt->lookup(i) != 0;
1271 }
1272 if( !has_target_ground ) {
1273 return -1;
1274 }
1275
1276 // calculate the minimal cuboid containing 'ziel'
1277 koord3d mini, maxi;
1278 get_mini_maxi( ziel, mini, maxi );
1279
1280 // memory in static list ...
1281 if(route_t::nodes==NULL) {
1282 route_t::MAX_STEP = welt->get_settings().get_max_route_steps(); // may need very much memory => configurable
1283 route_t::nodes = new route_t::ANode[route_t::MAX_STEP+4+1];
1284 }
1285
1286 static binary_heap_tpl <route_t::ANode *> queue;
1287
1288 // initialize marker field
1289 marker_t& marker = marker_t::instance(welt->get_size().x, welt->get_size().y);
1290
1291 // clear the queue (should be empty anyhow)
1292 queue.clear();
1293
1294 // some thing for the search
1295 grund_t *to;
1296 koord3d gr_pos; // just the last valid pos ...
1297 route_t::ANode *tmp=NULL;
1298 uint32 step = 0;
1299 const grund_t* gr=NULL;
1300
1301 FOR(vector_tpl<koord3d>, const& i, start) {
1302 gr = welt->lookup(i);
1303
1304 // is valid ground?
1305 sint32 dummy;
1306 if( !gr || !is_allowed_step(gr,gr,&dummy) ) {
1307 // DBG_MESSAGE("way_builder_t::intern_calc_route()","cannot start on (%i,%i,%i)",start.x,start.y,start.z);
1308 continue;
1309 }
1310 tmp = &(route_t::nodes[step]);
1311 step ++;
1312
1313 tmp->parent = NULL;
1314 tmp->gr = gr;
1315 tmp->f = calc_distance(i, mini, maxi);
1316 tmp->g = 0;
1317 tmp->dir = 0;
1318 tmp->count = 0;
1319
1320 queue.insert(tmp);
1321 }
1322
1323 if( queue.empty() ) {
1324 // no valid ground to start.
1325 return -1;
1326 }
1327
1328 INT_CHECK("wegbauer 347");
1329
1330 // get exclusively the tile list
1331 route_t::GET_NODE();
1332
1333 // to speed up search, but may not find all shortest ways
1334 uint32 min_dist = 99999999;
1335
1336 //DBG_MESSAGE("route_t::itern_calc_route()","calc route from %d,%d,%d to %d,%d,%d",ziel.x, ziel.y, ziel.z, start.x, start.y, start.z);
1337 do {
1338 route_t::ANode *test_tmp = queue.pop();
1339
1340 if(marker.test_and_mark(test_tmp->gr)) {
1341 // we were already here on a faster route, thus ignore this branch
1342 // (trading speed against memory consumption)
1343 continue;
1344 }
1345
1346 tmp = test_tmp;
1347 gr = tmp->gr;
1348 gr_pos = gr->get_pos();
1349
1350 #ifdef DEBUG_ROUTES
1351 DBG_DEBUG("insert to close","(%i,%i,%i) f=%i",gr->get_pos().x,gr->get_pos().y,gr->get_pos().z,tmp->f);
1352 #endif
1353
1354 // already there
1355 if( ziel.is_contained(gr_pos) || tmp->g>maximum) {
1356 // we added a target to the closed list: we are finished
1357 break;
1358 }
1359
1360 // the four possible directions plus any additional stuff due to already existing brides plus new ones ...
1361 next_gr.clear();
1362
1363 // only one direction allowed ...
1364 const ribi_t::ribi straight_dir = tmp->parent!=NULL ? ribi_type(gr->get_pos() - tmp->parent->gr->get_pos()) : (ribi_t::ribi)ribi_t::all;
1365
1366 // test directions
1367 // .. use only those that are allowed by current slope
1368 // .. do not go backward
1369 const ribi_t::ribi slope_dir = (slope_t::is_way_ns(gr->get_weg_hang()) ? ribi_t::northsouth : ribi_t::none) | (slope_t::is_way_ew(gr->get_weg_hang()) ? ribi_t::eastwest : ribi_t::none);
1370 const ribi_t::ribi test_dir = (tmp->count & build_straight)==0 ? slope_dir & ~ribi_t::backward(straight_dir)
1371 : straight_dir;
1372
1373 // testing all four possible directions
1374 for(ribi_t::ribi r=1; (r&16)==0; r<<=1) {
1375 if((r & test_dir)==0) {
1376 // not allowed to go this direction
1377 continue;
1378 }
1379
1380 bool do_terraform = false;
1381 const koord zv(r);
1382 if(!gr->get_neighbour(to,invalid_wt,r) || !check_slope(gr, to)) {
1383 // slopes do not match
1384 // terraforming enabled?
1385 if (bautyp==river || (bautyp & terraform_flag) == 0) {
1386 continue;
1387 }
1388 // check terraforming (but not in curves)
1389 if (gr->get_grund_hang()==0 || (tmp->parent!=NULL && tmp->parent->parent!=NULL && r==straight_dir)) {
1390 to = welt->lookup_kartenboden(gr->get_pos().get_2d() + zv);
1391 if (to==NULL || (check_slope(gr, to) && gr->get_vmove(r)!=to->get_vmove(ribi_t::backward(r)))) {
1392 continue;
1393 }
1394 else {
1395 do_terraform = true;
1396 }
1397 }
1398 else {
1399 continue;
1400 }
1401 }
1402
1403 // something valid?
1404 if(marker.is_marked(to)) {
1405 continue;
1406 }
1407
1408 sint32 new_cost = 0;
1409 bool is_ok = is_allowed_step(gr,to,&new_cost);
1410
1411 if(is_ok) {
1412 // now add it to the array ...
1413 next_gr.append(next_gr_t(to, new_cost, do_terraform ? build_straight | terraform : 0));
1414 }
1415 else if(tmp->parent!=NULL && r==straight_dir && (tmp->count & build_tunnel_bridge)==0) {
1416 // try to build a bridge or tunnel here, since we cannot go here ...
1417 check_for_bridge(tmp->parent->gr,gr,ziel);
1418 }
1419 }
1420
1421 // now check all valid ones ...
1422 FOR(vector_tpl<next_gr_t>, const& r, next_gr) {
1423 to = r.gr;
1424
1425 if( to==NULL) {
1426 continue;
1427 }
1428
1429 // new values for cost g
1430 uint32 new_g = tmp->g + r.cost;
1431
1432 settings_t const& s = welt->get_settings();
1433 // check for curves (usually, one would need the lastlast and the last;
1434 // if not there, then we could just take the last
1435 uint8 current_dir;
1436 if(tmp->parent!=NULL) {
1437 current_dir = ribi_type( tmp->parent->gr->get_pos(), to->get_pos() );
1438 if(tmp->dir!=current_dir) {
1439 new_g += s.way_count_curve;
1440 if(tmp->parent->dir!=tmp->dir) {
1441 // discourage double turns
1442 new_g += s.way_count_double_curve;
1443 }
1444 else if(ribi_t::is_perpendicular(tmp->dir,current_dir)) {
1445 // discourage v turns heavily
1446 new_g += s.way_count_90_curve;
1447 }
1448 }
1449 else if(bautyp==leitung && ribi_t::is_bend(current_dir)) {
1450 new_g += s.way_count_double_curve;
1451 }
1452 // extra malus leave an existing road after only one tile
1453 waytype_t const wt = desc->get_wtyp();
1454 if (tmp->parent->gr->hat_weg(wt) && !gr->hat_weg(wt) && to->hat_weg(wt)) {
1455 // but only if not straight track
1456 if(!ribi_t::is_straight(tmp->dir)) {
1457 new_g += s.way_count_leaving_road;
1458 }
1459 }
1460 }
1461 else {
1462 current_dir = ribi_type( gr->get_pos(), to->get_pos() );
1463 }
1464
1465 const uint32 new_dist = calc_distance( to->get_pos(), mini, maxi );
1466
1467 // special check for kinks at the end
1468 if(new_dist==0 && current_dir!=tmp->dir) {
1469 // discourage turn on last tile
1470 new_g += s.way_count_double_curve;
1471 }
1472
1473 if (new_dist == 0 && r.flag & terraform) {
1474 // no terraforming near target
1475 continue;
1476 }
1477 if(new_dist<min_dist) {
1478 min_dist = new_dist;
1479 }
1480 else if(new_dist>min_dist+50) {
1481 // skip, if too far from current minimum tile
1482 // will not find some ways, but will be much faster ...
1483 // also it will avoid too big detours, which is probably also not the way, the builder intended
1484 continue;
1485 }
1486
1487
1488 const uint32 new_f = new_g+new_dist;
1489
1490 if((step&0x03)==0) {
1491 INT_CHECK( "wegbauer 1347" );
1492 #ifdef DEBUG_ROUTES
1493 if((step&1023)==0) {minimap_t::get_karte()->calc_map();}
1494 #endif
1495 }
1496
1497 // not in there or taken out => add new
1498 route_t::ANode *k=&(route_t::nodes[step]);
1499 step++;
1500
1501 k->parent = tmp;
1502 k->gr = to;
1503 k->g = new_g;
1504 k->f = new_f;
1505 k->dir = current_dir;
1506 // count is unused here, use it as flag-variable instead
1507 k->count = r.flag;
1508
1509 queue.insert( k );
1510
1511 #ifdef DEBUG_ROUTES
1512 DBG_DEBUG("insert to open","(%i,%i,%i) f=%i",to->get_pos().x,to->get_pos().y,to->get_pos().z,k->f);
1513 #endif
1514 }
1515
1516 } while (!queue.empty() && step < route_t::MAX_STEP);
1517
1518 #ifdef DEBUG_ROUTES
1519 DBG_DEBUG("way_builder_t::intern_calc_route()","steps=%i (max %i) in route, open %i, cost %u",step,route_t::MAX_STEP,queue.get_count(),tmp->g);
1520 #endif
1521 INT_CHECK("wegbauer 194");
1522
1523 route_t::RELEASE_NODE();
1524
1525 // target reached?
1526 if( !ziel.is_contained(gr->get_pos()) || step>=route_t::MAX_STEP || tmp->parent==NULL || tmp->g > maximum ) {
1527 if (step>=route_t::MAX_STEP) {
1528 dbg->warning("way_builder_t::intern_calc_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,route_t::MAX_STEP);
1529 }
1530 return -1;
1531 }
1532 else {
1533 const sint32 cost = tmp->g;
1534 // reached => construct route
1535 while(tmp != NULL) {
1536 route.append(tmp->gr->get_pos());
1537 if (tmp->count & terraform) {
1538 terraform_index.append(route.get_count()-1);
1539 }
1540 tmp = tmp->parent;
1541 }
1542 return cost;
1543 }
1544
1545 return -1;
1546 }
1547
1548
intern_calc_straight_route(const koord3d start,const koord3d ziel)1549 void way_builder_t::intern_calc_straight_route(const koord3d start, const koord3d ziel)
1550 {
1551 bool ok = true;
1552 const koord3d koordup(0, 0, welt->get_settings().get_way_height_clearance());
1553
1554 sint32 dummy_cost;
1555 const grund_t *test_bd = welt->lookup(start);
1556 ok = false;
1557 if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost) ) {
1558 //there is a legal ground at the start
1559 ok = true;
1560 }
1561 if (ok && (bautyp&tunnel_flag) && !test_bd->ist_tunnel()) {
1562 // start tunnelbuilding in tunnels
1563 return;
1564 }
1565 if (bautyp&elevated_flag) {
1566 test_bd = welt->lookup(start + koordup);
1567 if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost, true) ) {
1568 //there is a legal way at the upper layer of start
1569 ok = true;
1570 }
1571 }
1572 if (!ok) {
1573 //target is not suitable
1574 return;
1575 }
1576 test_bd = welt->lookup(ziel);
1577 // we have to reach target height if no tunnel building or (target ground does not exists or is underground).
1578 // in full underground mode if there is no tunnel under cursor, kartenboden gets selected
1579 const bool target_3d = (bautyp&tunnel_flag)==0 || test_bd==NULL || !test_bd->ist_karten_boden();
1580 if((bautyp&tunnel_flag)==0) {
1581 //same thing to the target point
1582 ok = false;
1583 if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost) ) {
1584 //there is a legal ground at the target
1585 ok = true;
1586 }
1587 if (bautyp&elevated_flag) {
1588 test_bd = welt->lookup(ziel + koordup);
1589 if (test_bd && is_allowed_step(test_bd,test_bd,&dummy_cost, true) ) {
1590 //there is a legal way at the upper layer of the target
1591 ok = true;
1592 }
1593 }
1594 if(!ok) {
1595 return;
1596 }
1597 }
1598
1599 koord3d pos=start;
1600
1601 route.clear();
1602 route.append(start);
1603 terraform_index.clear();
1604 bool check_terraform = start.x==ziel.x || start.y==ziel.y;
1605
1606 while(pos.get_2d()!=ziel.get_2d() && ok) {
1607
1608 bool do_terraform = false;
1609 // shortest way
1610 ribi_t::ribi diff;
1611 if(abs(pos.x-ziel.x)>=abs(pos.y-ziel.y)) {
1612 diff = (pos.x>ziel.x) ? ribi_t::west : ribi_t::east;
1613 }
1614 else {
1615 diff = (pos.y>ziel.y) ? ribi_t::north : ribi_t::south;
1616 }
1617 if(bautyp&tunnel_flag) {
1618 // create fake tunnel grounds if needed
1619 bool bd_von_new = false, bd_nach_new = false;
1620 grund_t *bd_von = welt->lookup(pos);
1621 if( bd_von == NULL ) {
1622 bd_von = new tunnelboden_t(pos, slope_t::flat);
1623 bd_von_new = true;
1624 }
1625 // take care of slopes
1626 pos.z = bd_von->get_vmove(diff);
1627
1628 // check next tile
1629 grund_t *bd_nach = welt->lookup(pos + diff);
1630 if( !bd_nach ) {
1631 // check for slope down ...
1632 bd_nach = welt->lookup(pos + diff + koord3d(0,0,-1));
1633 if( !bd_nach ) {
1634 bd_nach = welt->lookup(pos + diff + koord3d(0,0,-2));
1635 }
1636 if( bd_nach && bd_nach->get_weg_hang() == slope_t::flat ) {
1637 // Don't care about _flat_ tunnels below.
1638 bd_nach = NULL;
1639 }
1640 }
1641 if( bd_nach == NULL ){
1642 bd_nach = new tunnelboden_t(pos + diff, slope_t::flat);
1643 bd_nach_new = true;
1644 }
1645 // check for tunnel and right slope
1646 ok = ok && bd_nach->ist_tunnel() && bd_nach->get_vmove(ribi_t::backward(diff))==pos.z;
1647 // all other checks are done here (crossings, stations etc)
1648 ok = ok && is_allowed_step(bd_von, bd_nach, &dummy_cost);
1649
1650 // advance position
1651 pos = bd_nach->get_pos();
1652
1653 // check new tile: ground must be above tunnel and below sea
1654 grund_t *gr = welt->lookup_kartenboden(pos.get_2d());
1655 ok = ok && (gr->get_hoehe() > pos.z) && (!gr->is_water() || (welt->lookup_hgt(pos.get_2d()) > pos.z) );
1656
1657 if (bd_von_new) {
1658 delete bd_von;
1659 }
1660 if (bd_nach_new) {
1661 delete bd_nach;
1662 }
1663 }
1664 else {
1665 grund_t *bd_von = welt->lookup(pos);
1666 ok = false;
1667 grund_t *bd_nach = NULL;
1668 if ( bd_von ) {
1669 if (bd_von->get_neighbour(bd_nach, invalid_wt, diff) && check_slope(bd_von, bd_nach)) {
1670 ok = true;
1671 }
1672 else {
1673 // slopes do not match
1674 // terraforming enabled? or able to follow upper layer?
1675 if ((bautyp==river || (bautyp & terraform_flag) == 0) && (bautyp&elevated_flag) == 0 ) {
1676 break;
1677 }
1678 // check terraforming (but not in curves)
1679 if (check_terraform) {
1680 bd_nach = welt->lookup_kartenboden(bd_von->get_pos().get_2d() + diff);
1681 if (bd_nach==NULL || (check_slope(bd_von, bd_nach) && bd_von->get_vmove(diff)!=bd_nach->get_vmove(ribi_t::backward(diff)))) {
1682 ok = false;
1683 }
1684 else {
1685 do_terraform = true;
1686 ok = true;
1687 }
1688 }
1689 }
1690 // allowed ground?
1691 ok = ok && bd_nach && is_allowed_step(bd_von,bd_nach,&dummy_cost);
1692 if (ok) {
1693 pos = bd_nach->get_pos();
1694 }
1695 }
1696 // if failed
1697 if (!ok && bautyp&elevated_flag) {
1698 //search following the upper layer
1699 bd_von = welt->lookup(pos + koordup);
1700 if(bd_von && bd_von->get_neighbour(bd_nach, invalid_wt, diff) && check_slope(bd_von, bd_nach) && is_allowed_step(bd_von, bd_nach, &dummy_cost, true) ) {
1701 ok = true;
1702 pos = bd_nach->get_pos() - koordup;
1703 }
1704 }
1705 check_terraform = pos.x==ziel.x || pos.y==ziel.y;
1706 }
1707
1708 route.append(pos);
1709 if (do_terraform) {
1710 terraform_index.append(route.get_count()-2);
1711 }
1712 DBG_MESSAGE("way_builder_t::calc_straight_route()","step %s = %i",koord(diff).get_str(),ok);
1713 }
1714 ok = ok && ( target_3d ? pos==ziel : pos.get_2d()==ziel.get_2d() );
1715
1716 // we can built a straight route?
1717 if(ok) {
1718 DBG_MESSAGE("way_builder_t::intern_calc_straight_route()","found straight route max_n=%i",get_count()-1);
1719 }
1720 else {
1721 route.clear();
1722 terraform_index.clear();
1723 }
1724 }
1725
1726 /* this routine uses A* to calculate the best route
1727 * beware: change the cost and you will mess up the system!
1728 * (but you can try, look at simuconf.tab)
1729 */
1730 /* It should not be river/airport/tunnel/bridge/terraformable
1731 */
intern_calc_route_elevated(const koord3d start,const koord3d ziel)1732 sint32 way_builder_t::intern_calc_route_elevated(const koord3d start, const koord3d ziel)
1733 {
1734 // we clear it here probably twice: does not hurt ...
1735 route.clear();
1736 terraform_index.clear();
1737
1738 const koord3d koordup(0, 0, welt->get_settings().get_way_height_clearance());
1739
1740 // check for existing koordinates
1741 bool has_target_ground = welt->lookup(ziel) || welt->lookup(ziel + koordup);
1742 if( !has_target_ground ) {
1743 return -1;
1744 }
1745
1746
1747 // memory in static list ...
1748 if(route_t::nodes==NULL) {
1749 route_t::MAX_STEP = welt->get_settings().get_max_route_steps(); // may need very much memory => configurable
1750 route_t::nodes = new route_t::ANode[route_t::MAX_STEP+4+1];
1751 }
1752
1753 static binary_heap_tpl <route_t::ANode *> queue;
1754
1755 // initialize marker field
1756 marker_t& markerbelow = marker_t::instance(welt->get_size().x, welt->get_size().y);
1757 marker_t& markerabove = marker_t::instance_second(welt->get_size().x, welt->get_size().y);
1758
1759 // clear the queue (should be empty anyhow)
1760 queue.clear();
1761
1762 // some thing for the search
1763 grund_t *to;
1764 koord3d gr_pos; // just the last valid pos ...
1765 route_t::ANode *tmp=NULL;
1766 uint32 step = 0;
1767 const grund_t *gr=NULL, *gu = NULL;
1768
1769 gr = welt->lookup(start);
1770 // is valid ground?
1771 sint32 dummy;
1772 if( gr && is_allowed_step(gr,gr,&dummy) ) {
1773 // DBG_MESSAGE("way_builder_t::intern_calc_route()","cannot start on (%i,%i,%i)",start.x,start.y,start.z);
1774 tmp = &(route_t::nodes[step]);
1775 step ++;
1776 tmp->parent = NULL;
1777 tmp->gr = gr;
1778 tmp->f = calc_distance(start, ziel, ziel);
1779 tmp->g = 0;
1780 tmp->dir = 0;
1781
1782 tmp->count = 0;
1783
1784 queue.insert(tmp);
1785 }
1786
1787 gu = welt->lookup(start + koordup);
1788 if( gu && is_allowed_step(gu,gu,&dummy, true) ) {
1789 // DBG_MESSAGE("way_builder_t::intern_calc_route()","cannot start on (%i,%i,%i)",start.x,start.y,start.z);
1790 tmp = &(route_t::nodes[step]);
1791 step ++;
1792 tmp->parent = NULL;
1793 tmp->gr = gu;
1794 tmp->f = calc_distance(start, ziel, ziel);
1795 tmp->g = 0;
1796 tmp->dir = 0;
1797
1798 tmp->count = is_upperlayer;
1799
1800 queue.insert(tmp);
1801 }
1802
1803
1804 if( queue.empty() ) {
1805 // no valid ground to start.
1806 return -1;
1807 }
1808
1809 INT_CHECK("wegbauer 347");
1810
1811 // get exclusively the tile list
1812 route_t::GET_NODE();
1813
1814 // to speed up search, but may not find all shortest ways
1815 uint32 min_dist = 99999999;
1816
1817 //DBG_MESSAGE("route_t::itern_calc_route()","calc route from %d,%d,%d to %d,%d,%d",ziel.x, ziel.y, ziel.z, start.x, start.y, start.z);
1818 do {
1819 route_t::ANode *test_tmp = queue.pop();
1820
1821 if( (test_tmp->count&is_upperlayer?markerabove:markerbelow).test_and_mark(test_tmp->gr) ) {
1822 // we were already here on a faster route, thus ignore this branch
1823 // (trading speed against memory consumption)
1824 continue;
1825 }
1826
1827 tmp = test_tmp;
1828 if(test_tmp->count & is_upperlayer) {
1829 gu = tmp->gr;
1830 gr_pos = gu->get_pos() - koordup;
1831 gr = welt->lookup(gr_pos);
1832 }
1833 else {
1834 gr = tmp->gr;
1835 gr_pos = gr->get_pos();
1836 gu = welt->lookup(gr_pos + koordup);
1837 }
1838
1839 #ifdef DEBUG_ROUTES
1840 DBG_DEBUG("insert to close","(%i,%i,%i) f=%i",gr->get_pos().x,gr->get_pos().y,gr->get_pos().z,tmp->f);
1841 #endif
1842
1843 // already there
1844 if( ziel == gr_pos || tmp->g>maximum) {
1845 // we added a target to the closed list: we are finished
1846 break;
1847 }
1848
1849 // the four possible directions plus any additional stuff due to already existing brides plus new ones ...
1850 next_gr.clear();
1851
1852 //search following the lower layer
1853 if(gr) {
1854
1855 // only one direction allowed ...
1856 const ribi_t::ribi straight_dir = tmp->parent!=NULL ? ribi_type(gr->get_pos() - tmp->parent->gr->get_pos()) : (ribi_t::ribi)ribi_t::all;
1857
1858 // test directions
1859 // .. use only those that are allowed by current slope
1860 // .. do not go backward
1861 const ribi_t::ribi slope_dir = (slope_t::is_way_ns(gr->get_weg_hang()) ? ribi_t::northsouth : ribi_t::none) | (slope_t::is_way_ew(gr->get_weg_hang()) ? ribi_t::eastwest : ribi_t::none);
1862 const ribi_t::ribi test_dir = (tmp->count & build_straight)==0 ? slope_dir & ~ribi_t::backward(straight_dir)
1863 : straight_dir;
1864
1865 // testing all four possible directions
1866 for(ribi_t::ribi r=1; (r&16)==0; r<<=1) {
1867 if((r & test_dir)==0) {
1868 // not allowed to go this direction
1869 continue;
1870 }
1871
1872 const koord zv(r);
1873 if(!gr->get_neighbour(to,invalid_wt,r) || !check_slope(gr, to)) {
1874 // slopes do not match
1875 continue;
1876 }
1877
1878 // something valid?
1879 if(markerbelow.is_marked(to)) {
1880 continue;
1881 }
1882
1883 sint32 new_cost = 0;
1884 bool is_ok = is_allowed_step(gr,to,&new_cost);
1885
1886 if(is_ok) {
1887 // now add it to the array ...
1888 next_gr.append(next_gr_t(to, new_cost, 0));
1889 }
1890 }
1891 }
1892
1893 //search following the upper layer
1894 if(gu) {
1895
1896 // only one direction allowed ...
1897 const ribi_t::ribi straight_dir = tmp->parent!=NULL ? ribi_type(gu->get_pos() - tmp->parent->gr->get_pos()) : (ribi_t::ribi)ribi_t::all;
1898
1899 // test directions
1900 // .. use only those that are allowed by current slope
1901 // .. do not go backward
1902 const ribi_t::ribi slope_dir = (slope_t::is_way_ns(gu->get_weg_hang()) ? ribi_t::northsouth : ribi_t::none) | (slope_t::is_way_ew(gu->get_weg_hang()) ? ribi_t::eastwest : ribi_t::none);
1903 const ribi_t::ribi test_dir = (tmp->count & build_straight)==0 ? slope_dir & ~ribi_t::backward(straight_dir)
1904 : straight_dir;
1905
1906 // testing all four possible directions
1907 for(ribi_t::ribi r=1; (r&16)==0; r<<=1) {
1908 if((r & test_dir)==0) {
1909 // not allowed to go this direction
1910 continue;
1911 }
1912
1913 const koord zv(r);
1914 if(!gu->get_neighbour(to,invalid_wt,r) || !check_slope(gu, to)) {
1915 // slopes do not match
1916 continue;
1917 }
1918
1919 // something valid?
1920 if(markerabove.is_marked(to)) {
1921 continue;
1922 }
1923
1924 sint32 new_cost = 0;
1925 bool is_ok = is_allowed_step(gu,to,&new_cost, true);
1926
1927 if(is_ok) {
1928 // now add it to the array ...
1929 next_gr.append(next_gr_t(to, new_cost, is_upperlayer));
1930 }
1931 }
1932 }
1933
1934 // now check all valid ones ...
1935 FOR(vector_tpl<next_gr_t>, const& r, next_gr) {
1936 to = r.gr;
1937
1938 if( to==NULL) {
1939 continue;
1940 }
1941
1942 // new values for cost g
1943 uint32 new_g = tmp->g + r.cost;
1944
1945 settings_t const& s = welt->get_settings();
1946 // check for curves (usually, one would need the lastlast and the last;
1947 // if not there, then we could just take the last
1948 uint8 current_dir;
1949 if(tmp->parent!=NULL) {
1950 current_dir = ribi_type( tmp->parent->gr->get_pos(), to->get_pos() );
1951 if(tmp->dir!=current_dir) {
1952 new_g += s.way_count_curve;
1953 if(tmp->parent->dir!=tmp->dir) {
1954 // discourage double turns
1955 new_g += s.way_count_double_curve;
1956 }
1957 else if(ribi_t::is_perpendicular(tmp->dir,current_dir)) {
1958 // discourage v turns heavily
1959 new_g += s.way_count_90_curve;
1960 }
1961 }
1962 else if(bautyp==leitung && ribi_t::is_bend(current_dir)) {
1963 new_g += s.way_count_double_curve;
1964 }
1965 // extra malus leave an existing road after only one tile
1966 waytype_t const wt = desc->get_wtyp();
1967 if (tmp->parent->gr->hat_weg(wt) && !(gr? gr: gu)->hat_weg(wt) && to->hat_weg(wt)) {
1968 // but only if not straight track
1969 if(!ribi_t::is_straight(tmp->dir)) {
1970 new_g += s.way_count_leaving_road;
1971 }
1972 }
1973 }
1974 else {
1975 current_dir = ribi_type( gr_pos, to->get_pos() );
1976 }
1977
1978 const uint32 new_dist = calc_distance( to->get_pos(), ziel, ziel );
1979
1980 // special check for kinks at the end
1981 if(new_dist==0 && current_dir!=tmp->dir) {
1982 // discourage turn on last tile
1983 new_g += s.way_count_double_curve;
1984 }
1985
1986 if(new_dist<min_dist) {
1987 min_dist = new_dist;
1988 }
1989 else if(new_dist>min_dist+50) {
1990 // skip, if too far from current minimum tile
1991 // will not find some ways, but will be much faster ...
1992 // also it will avoid too big detours, which is probably also not the way, the builder intended
1993 continue;
1994 }
1995
1996
1997 const uint32 new_f = new_g+new_dist;
1998
1999 if((step&0x03)==0) {
2000 INT_CHECK( "wegbauer 1347" );
2001 #ifdef DEBUG_ROUTES
2002 if((step&1023)==0) {minimap_t::get_karte()->calc_map();}
2003 #endif
2004 }
2005
2006 // not in there or taken out => add new
2007 route_t::ANode *k=&(route_t::nodes[step]);
2008 step++;
2009
2010 k->parent = tmp;
2011 k->gr = to;
2012 k->g = new_g;
2013 k->f = new_f;
2014 k->dir = current_dir;
2015 // count is unused here, use it as flag-variable instead
2016 k->count = r.flag;
2017
2018 queue.insert( k );
2019
2020 #ifdef DEBUG_ROUTES
2021 DBG_DEBUG("insert to open","(%i,%i,%i) f=%i",to->get_pos().x,to->get_pos().y,to->get_pos().z,k->f);
2022 #endif
2023 }
2024
2025 } while (!queue.empty() && step < route_t::MAX_STEP);
2026
2027 #ifdef DEBUG_ROUTES
2028 DBG_DEBUG("way_builder_t::intern_calc_route()","steps=%i (max %i) in route, open %i, cost %u",step,route_t::MAX_STEP,queue.get_count(),tmp->g);
2029 #endif
2030 INT_CHECK("wegbauer 194");
2031
2032 route_t::RELEASE_NODE();
2033
2034 // target reached?
2035 if( !(ziel == gr_pos) || step>=route_t::MAX_STEP || tmp->parent==NULL || tmp->g > maximum ) {
2036 if (step>=route_t::MAX_STEP) {
2037 dbg->warning("way_builder_t::intern_calc_route()","Too many steps (%i>=max %i) in route (too long/complex)",step,route_t::MAX_STEP);
2038 }
2039 return -1;
2040 }
2041 else {
2042 const sint32 cost = tmp->g;
2043 // reached => construct route
2044 while(tmp != NULL) {
2045 if(tmp->count & is_upperlayer) {
2046 route.append(tmp->gr->get_pos() - koordup);
2047 } else {
2048 route.append(tmp->gr->get_pos() );
2049 }
2050 tmp = tmp->parent;
2051 }
2052 return cost;
2053 }
2054
2055 return -1;
2056 }
2057
2058
2059 // special for starting/landing runways
intern_calc_route_runways(koord3d start3d,const koord3d ziel3d)2060 bool way_builder_t::intern_calc_route_runways(koord3d start3d, const koord3d ziel3d)
2061 {
2062 route.clear();
2063 terraform_index.clear();
2064
2065 const koord start=start3d.get_2d();
2066 const koord ziel=ziel3d.get_2d();
2067 // check for straight line!
2068 const ribi_t::ribi ribi = ribi_type( start, ziel );
2069 if( !ribi_t::is_straight(ribi) ) {
2070 // only straight runways!
2071 return false;
2072 }
2073 const ribi_t::ribi ribi_straight = ribi_t::doubles(ribi);
2074
2075 // not too close to the border?
2076 if( !(welt->is_within_limits(start-koord(5,5)) && welt->is_within_limits(start+koord(5,5))) ||
2077 !(welt->is_within_limits(ziel-koord(5,5)) && welt->is_within_limits(ziel+koord(5,5))) ) {
2078 if(player_builder==welt->get_active_player()) {
2079 create_win( new news_img("Zu nah am Kartenrand"), w_time_delete, magic_none);
2080 return false;
2081 }
2082 }
2083
2084 // now try begin and endpoint
2085 const koord zv(ribi);
2086 // end start
2087 const grund_t *gr = welt->lookup_kartenboden(start);
2088 const weg_t *weg = gr->get_weg(air_wt);
2089 if(weg && !ribi_t::is_straight(weg->get_ribi()|ribi_straight) ) {
2090 // cannot connect with curve at the end
2091 return false;
2092 }
2093 if( weg && weg->get_desc()->get_styp()==type_flat ) {
2094 // could not continue taxiway with runway
2095 return false;
2096 }
2097 // check end
2098 gr = welt->lookup_kartenboden(ziel);
2099 weg = gr->get_weg(air_wt);
2100 if(weg && !ribi_t::is_straight(weg->get_ribi()|ribi_straight) ) {
2101 // cannot connect with curve at the end
2102 return false;
2103 }
2104 if( weg && weg->get_desc()->get_styp()==type_flat ) {
2105 // could not continue taxiway with runway
2106 return false;
2107 }
2108 // now try a straight line with no crossings and no curves at the end
2109 const int dist=koord_distance( ziel, start );
2110 grund_t *from = welt->lookup_kartenboden(start);
2111 for( int i=0; i<=dist; i++ ) {
2112 grund_t *to = welt->lookup_kartenboden(start+zv*i);
2113 sint32 dummy;
2114 if (!is_allowed_step(from, to, &dummy)) {
2115 return false;
2116 }
2117 weg = to->get_weg(air_wt);
2118 if( weg && weg->get_desc()->get_styp()==type_runway && (ribi_t::is_threeway(weg->get_ribi_unmasked()|ribi_straight)) && (weg->get_ribi_unmasked()|ribi_straight)!=ribi_t::all ) {
2119 // only fourway crossings of runways allowed, no threeways => fail
2120 return false;
2121 }
2122 from = to;
2123 }
2124 // now we can build here
2125 route.clear();
2126 terraform_index.clear();
2127 route.resize(dist + 2);
2128 for( int i=0; i<=dist; i++ ) {
2129 route.append(welt->lookup_kartenboden(start + zv * i)->get_pos());
2130 }
2131 return true;
2132 }
2133
2134
2135 /*
2136 * calc_straight_route (maximum one curve, including diagonals)
2137 */
calc_straight_route(koord3d start,const koord3d ziel)2138 void way_builder_t::calc_straight_route(koord3d start, const koord3d ziel)
2139 {
2140 DBG_MESSAGE("way_builder_t::calc_straight_route()","from %d,%d,%d to %d,%d,%d",start.x,start.y,start.z, ziel.x,ziel.y,ziel.z );
2141 if(bautyp==luft && desc->get_styp()==type_runway) {
2142 // these are straight anyway ...
2143 intern_calc_route_runways(start, ziel);
2144 }
2145 else {
2146 intern_calc_straight_route(start,ziel);
2147 if (route.empty()) {
2148 intern_calc_straight_route(ziel,start);
2149 }
2150 }
2151 }
2152
2153
calc_route(const koord3d & start,const koord3d & ziel)2154 void way_builder_t::calc_route(const koord3d &start, const koord3d &ziel)
2155 {
2156 vector_tpl<koord3d> start_vec(1), ziel_vec(1);
2157 start_vec.append(start);
2158 ziel_vec.append(ziel);
2159 calc_route(start_vec, ziel_vec);
2160 }
2161
2162 /* calc_route
2163 *
2164 */
calc_route(const vector_tpl<koord3d> & start,const vector_tpl<koord3d> & ziel)2165 void way_builder_t::calc_route(const vector_tpl<koord3d> &start, const vector_tpl<koord3d> &ziel)
2166 {
2167 #ifdef DEBUG_ROUTES
2168 uint32 ms = dr_time();
2169 #endif
2170 INT_CHECK("simbau 740");
2171
2172 if(bautyp==luft && desc->get_styp()==type_runway) {
2173 assert( start.get_count() == 1 && ziel.get_count() == 1 );
2174 intern_calc_route_runways(start[0], ziel[0]);
2175 }
2176 else if(bautyp==river) {
2177 assert( start.get_count() == 1 && ziel.get_count() == 1 );
2178 // river only go downwards => start and end are clear ...
2179 if( start[0].z > ziel[0].z ) {
2180 intern_calc_route( start, ziel );
2181 }
2182 else {
2183 intern_calc_route( ziel, start );
2184 }
2185 while (route.get_count()>1 && welt->lookup(route[0])->get_grund_hang() == slope_t::flat && welt->lookup(route[1])->is_water()) {
2186 // remove leading water ...
2187 route.remove_at(0);
2188 }
2189 }
2190 else {
2191 keep_existing_city_roads |= (bautyp&bot_flag)!=0;
2192 sint32 cost2;
2193 if(desc->get_styp() == type_elevated) {
2194 cost2 = intern_calc_route_elevated(start[0], ziel[0]);
2195 INT_CHECK("wegbauer 1165");
2196 if(cost2 < 0) {
2197 intern_calc_route_elevated(ziel[0], start[0]);
2198 return;
2199 }
2200 }
2201 else {
2202 cost2 = intern_calc_route( start, ziel );
2203 INT_CHECK("wegbauer 1165");
2204 if(cost2 < 0) {
2205 intern_calc_route( ziel, start );
2206 return;
2207 }
2208 }
2209
2210 #ifdef REVERSE_CALC_ROUTE_TOO
2211 vector_tpl<koord3d> route2(0);
2212 vector_tpl<uint32> terraform_index2(0);
2213 swap(route, route2);
2214 swap(terraform_index, terraform_index2);
2215 sint32 cost;
2216 if(desc->get_styp() == type_elevated) {
2217 cost = intern_calc_route_elevated(start[0], ziel[0]);
2218 }
2219 else {
2220 cost = intern_calc_route( start, ziel );
2221 }
2222 INT_CHECK("wegbauer 1165");
2223
2224 // the cheaper will survive ...
2225 if( cost2 < cost || cost < 0 ) {
2226 swap(route, route2);
2227 swap(terraform_index, terraform_index2);
2228 }
2229 #endif
2230 }
2231 INT_CHECK("wegbauer 778");
2232 #ifdef DEBUG_ROUTES
2233 DBG_MESSAGE("calc_route::calc_route", "took %u ms", dr_time() - ms );
2234 #endif
2235 }
2236
2237
build_tunnel_and_bridges()2238 void way_builder_t::build_tunnel_and_bridges()
2239 {
2240 if(bridge_desc==NULL && tunnel_desc==NULL) {
2241 return;
2242 }
2243 // check for bridges and tunnels (no tunnel/bridge at last/first tile)
2244 for(uint32 i=1; i<get_count()-2; i++) {
2245 koord d = (route[i + 1] - route[i]).get_2d();
2246 koord zv = koord (sgn(d.x), sgn(d.y));
2247
2248 // ok, here is a gap ...
2249 if(d.x > 1 || d.y > 1 || d.x < -1 || d.y < -1) {
2250
2251 if(d.x*d.y!=0) {
2252 dbg->error("way_builder_t::build_tunnel_and_bridges()","cannot built a bridge between %s (n=%i, max_n=%i) and %s", route[i].get_str(),i,get_count()-1,route[i+1].get_str());
2253 continue;
2254 }
2255
2256 DBG_MESSAGE("way_builder_t::build_tunnel_and_bridges", "built bridge %p between %s and %s", bridge_desc, route[i].get_str(), route[i + 1].get_str());
2257
2258 const grund_t* start = welt->lookup(route[i]);
2259 const grund_t* end = welt->lookup(route[i + 1]);
2260
2261 if(start->get_weg_hang()!=start->get_grund_hang()) {
2262 // already a bridge/tunnel there ...
2263 continue;
2264 }
2265 if(end->get_weg_hang()!=end->get_grund_hang()) {
2266 // already a bridge/tunnel there ...
2267 continue;
2268 }
2269
2270 if(start->get_grund_hang()==0 || start->get_grund_hang()==slope_type(zv*(-1))) {
2271 // bridge here, since the route is saved backwards, we have to build it at the posterior end
2272 bridge_builder_t::build( player_builder, route[i+1], bridge_desc);
2273 }
2274 else {
2275 // tunnel
2276 tunnel_builder_t::build( player_builder, route[i].get_2d(), tunnel_desc, true );
2277 }
2278 INT_CHECK( "wegbauer 1584" );
2279 }
2280 // Don't build short tunnels/bridges if they block a bridge/tunnel behind!
2281 else if( bautyp != leitung && koord_distance(route[i + 2], route[i + 1]) == 1 ) {
2282 grund_t *gr_i = welt->lookup(route[i]);
2283 grund_t *gr_i1 = welt->lookup(route[i+1]);
2284 if( gr_i->get_weg_hang() != gr_i->get_grund_hang() || gr_i1->get_weg_hang() != gr_i1->get_grund_hang() ) {
2285 // Here is already a tunnel or a bridge.
2286 continue;
2287 }
2288 slope_t::type h = gr_i->get_weg_hang();
2289 waytype_t const wt = desc->get_wtyp();
2290 if(h!=slope_t::flat && slope_t::opposite(h)==gr_i1->get_weg_hang()) {
2291 // either a short mountain or a short dip ...
2292 // now: check ownership
2293 weg_t *wi = gr_i->get_weg(wt);
2294 weg_t *wi1 = gr_i1->get_weg(wt);
2295 if(wi->get_owner()==player_builder && wi1->get_owner()==player_builder) {
2296 // we are the owner
2297 if( h != slope_type(zv) ) {
2298 // its a bridge
2299 if( bridge_desc ) {
2300 wi->set_ribi(ribi_type(h));
2301 wi1->set_ribi(ribi_type(slope_t::opposite(h)));
2302 bridge_builder_t::build( player_builder, route[i], bridge_desc);
2303 }
2304 }
2305 else if( tunnel_desc ) {
2306 // make a short tunnel
2307 wi->set_ribi(ribi_type(slope_t::opposite(h)));
2308 wi1->set_ribi(ribi_type(h));
2309 tunnel_builder_t::build( player_builder, route[i].get_2d(), tunnel_desc, true );
2310 }
2311 INT_CHECK( "wegbauer 1584" );
2312 }
2313 }
2314 }
2315 }
2316 }
2317
2318
2319 /*
2320 * returns the amount needed to built this way
2321 * author prissi
2322 */
calc_costs()2323 sint64 way_builder_t::calc_costs()
2324 {
2325 sint64 costs=0;
2326 koord3d offset = koord3d( 0, 0, bautyp & elevated_flag ? welt->get_settings().get_way_height_clearance() : 0 );
2327
2328 sint32 single_cost;
2329 sint32 new_speedlimit;
2330
2331 if( bautyp&tunnel_flag ) {
2332 assert( tunnel_desc );
2333 single_cost = tunnel_desc->get_price();
2334 new_speedlimit = tunnel_desc->get_topspeed();
2335 }
2336 else {
2337 single_cost = desc->get_price();
2338 new_speedlimit = desc->get_topspeed();
2339 }
2340
2341 // calculate costs for terraforming
2342 uint32 last_terraformed = terraform_index.get_count();
2343
2344 FOR(vector_tpl<uint32>, const i, terraform_index) { // index in route
2345 grund_t *from = welt->lookup(route[i]);
2346 uint8 from_slope = from->get_grund_hang();
2347
2348 grund_t *to = welt->lookup(route[i+1]);
2349 uint8 to_slope = to->get_grund_hang();
2350 // calculate new slopes
2351 check_terraforming(from, to, &from_slope, &to_slope);
2352 // change slope of from
2353 if (from_slope != from->get_grund_hang()) {
2354 if (last_terraformed != i) {
2355 costs -= welt->get_settings().cst_set_slope;
2356 }
2357 }
2358 // change slope of to
2359 if (to_slope != to->get_grund_hang()) {
2360 costs -= welt->get_settings().cst_set_slope;
2361 last_terraformed = i+1; // do not pay twice for terraforming one tile
2362 }
2363 }
2364
2365 for(uint32 i=0; i<get_count(); i++) {
2366 sint32 old_speedlimit = -1;
2367 sint32 replace_cost = 0;
2368
2369 const grund_t* gr = welt->lookup(route[i] + offset);
2370 if( gr ) {
2371 if( bautyp&tunnel_flag ) {
2372 const tunnel_t *tunnel = gr->find<tunnel_t>();
2373 assert( tunnel );
2374 if( tunnel->get_desc() == tunnel_desc ) {
2375 continue; // Nothing to pay on this tile.
2376 }
2377 old_speedlimit = tunnel->get_desc()->get_topspeed();
2378 }
2379 else {
2380 if( desc->get_wtyp() == powerline_wt ) {
2381 if( leitung_t *lt=gr->get_leitung() ) {
2382 old_speedlimit = lt->get_desc()->get_topspeed();
2383 }
2384 }
2385 else {
2386 if (weg_t const* const weg = gr->get_weg(desc->get_wtyp())) {
2387 replace_cost = weg->get_desc()->get_price();
2388 if( weg->get_desc() == desc ) {
2389 continue; // Nothing to pay on this tile.
2390 }
2391 if( desc->get_styp() == type_flat && weg->get_desc()->get_styp() == type_tram && gr->get_weg_nr(0)->get_waytype() == road_wt ) {
2392 // Don't replace a tram on a road with a normal track.
2393 continue;
2394 }
2395 old_speedlimit = weg->get_desc()->get_topspeed();
2396 }
2397 else if (desc->get_wtyp()==water_wt && gr->is_water()) {
2398 old_speedlimit = new_speedlimit;
2399 }
2400 }
2401 }
2402 // eventually we have to remove trees
2403 for( uint8 i=0; i<gr->get_top(); i++ ) {
2404 obj_t *obj = gr->obj_bei(i);
2405 switch(obj->get_typ()) {
2406 case obj_t::baum:
2407 costs -= welt->get_settings().cst_remove_tree;
2408 break;
2409 case obj_t::groundobj:
2410 costs += ((groundobj_t *)obj)->get_desc()->get_price();
2411 break;
2412 default: break;
2413 }
2414 }
2415 }
2416 if( !keep_existing_faster_ways || old_speedlimit < new_speedlimit ) {
2417 costs += max(single_cost, replace_cost);
2418 }
2419
2420 // last tile cannot be start of tunnel/bridge
2421 if(i+1<get_count()) {
2422 koord d = (route[i + 1] - route[i]).get_2d();
2423 // ok, here is a gap ... => either bridge or tunnel
2424 if(d.x > 1 || d.y > 1 || d.x < -1 || d.y < -1) {
2425 koord zv = koord (sgn(d.x), sgn(d.y));
2426 const grund_t* start = welt->lookup(route[i]);
2427 const grund_t* end = welt->lookup(route[i + 1]);
2428 if(start->get_weg_hang()!=start->get_grund_hang()) {
2429 // already a bridge/tunnel there ...
2430 continue;
2431 }
2432 if(end->get_weg_hang()!=end->get_grund_hang()) {
2433 // already a bridge/tunnel there ...
2434 continue;
2435 }
2436 if(start->get_grund_hang()==0 || start->get_grund_hang()==slope_type(zv*(-1))) {
2437 // bridge
2438 costs += bridge_desc->get_price()*(sint64)(koord_distance(route[i], route[i+1])+1);
2439 continue;
2440 }
2441 else {
2442 // tunnel
2443 costs += tunnel_desc->get_price()*(sint64)(koord_distance(route[i], route[i+1])+1);
2444 continue;
2445 }
2446 }
2447 }
2448 }
2449 DBG_MESSAGE("way_builder_t::calc_costs()","construction estimate: %f",costs/100.0);
2450 return costs;
2451 }
2452
2453
2454 // adds the ground before underground construction
build_tunnel_tile()2455 bool way_builder_t::build_tunnel_tile()
2456 {
2457 sint64 cost = 0;
2458 for(uint32 i=0; i<get_count(); i++) {
2459
2460 grund_t* gr = welt->lookup(route[i]);
2461
2462 const way_desc_t *wb = tunnel_desc->get_way_desc();
2463 if(wb==NULL) {
2464 // now we search a matching way for the tunnels top speed
2465 // ignore timeline to get consistent results
2466 wb = way_builder_t::weg_search( tunnel_desc->get_waytype(), tunnel_desc->get_topspeed(), 0, type_flat );
2467 }
2468
2469 if(gr==NULL) {
2470 // make new tunnelboden
2471 tunnelboden_t* tunnel = new tunnelboden_t(route[i], 0);
2472 welt->access(route[i].get_2d())->boden_hinzufuegen(tunnel);
2473 if( tunnel_desc->get_waytype() != powerline_wt ) {
2474 weg_t *weg = weg_t::alloc(tunnel_desc->get_waytype());
2475 weg->set_desc( wb );
2476 tunnel->neuen_weg_bauen(weg, route.get_ribi(i), player_builder);
2477 tunnel->obj_add(new tunnel_t(route[i], player_builder, tunnel_desc));
2478 weg->set_max_speed(tunnel_desc->get_topspeed());
2479 player_t::add_maintenance( player_builder, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
2480 }
2481 else {
2482 tunnel->obj_add(new tunnel_t(route[i], player_builder, tunnel_desc));
2483 leitung_t *lt = new leitung_t(tunnel->get_pos(), player_builder);
2484 lt->set_desc( wb );
2485 tunnel->obj_add( lt );
2486 lt->finish_rd();
2487 player_t::add_maintenance( player_builder, -lt->get_desc()->get_maintenance(), powerline_wt);
2488 }
2489 tunnel->calc_image();
2490 cost -= tunnel_desc->get_price();
2491 player_t::add_maintenance( player_builder, tunnel_desc->get_maintenance(), tunnel_desc->get_finance_waytype() );
2492 }
2493 else if( gr->get_typ() == grund_t::tunnelboden ) {
2494 // check for extension only ...
2495 if( tunnel_desc->get_waytype() != powerline_wt ) {
2496 gr->weg_erweitern( tunnel_desc->get_waytype(), route.get_ribi(i) );
2497
2498 tunnel_t *tunnel = gr->find<tunnel_t>();
2499 assert( tunnel );
2500 // take the faster way
2501 if( !keep_existing_faster_ways || (tunnel->get_desc()->get_topspeed() < tunnel_desc->get_topspeed()) ) {
2502 player_t::add_maintenance(player_builder, -tunnel->get_desc()->get_maintenance(), tunnel->get_desc()->get_finance_waytype());
2503 player_t::add_maintenance(player_builder, tunnel_desc->get_maintenance(), tunnel->get_desc()->get_finance_waytype() );
2504
2505 tunnel->set_desc(tunnel_desc);
2506 weg_t *weg = gr->get_weg(tunnel_desc->get_waytype());
2507 weg->set_desc(wb);
2508 weg->set_max_speed(tunnel_desc->get_topspeed());
2509 // respect max speed of catenary
2510 wayobj_t const* const wo = gr->get_wayobj(tunnel_desc->get_waytype());
2511 if (wo && wo->get_desc()->get_topspeed() < weg->get_max_speed()) {
2512 weg->set_max_speed( wo->get_desc()->get_topspeed() );
2513 }
2514 gr->calc_image();
2515 // respect speed limit of crossing
2516 weg->count_sign();
2517
2518 cost -= tunnel_desc->get_price();
2519 }
2520 }
2521 else {
2522 leitung_t *lt = gr->get_leitung();
2523 if(!lt) {
2524 lt = new leitung_t(gr->get_pos(), player_builder);
2525 lt->set_desc( wb );
2526 gr->obj_add( lt );
2527 }
2528 else {
2529 lt->leitung_t::finish_rd(); // only change powerline aspect
2530 player_t::add_maintenance( player_builder, -lt->get_desc()->get_maintenance(), powerline_wt);
2531 }
2532 }
2533 }
2534 }
2535 player_t::book_construction_costs(player_builder, cost, route[0].get_2d(), tunnel_desc->get_waytype());
2536 return true;
2537 }
2538
2539
2540
build_elevated()2541 void way_builder_t::build_elevated()
2542 {
2543 FOR(koord3d_vector_t, & i, route) {
2544 planquadrat_t* const plan = welt->access(i.get_2d());
2545
2546 grund_t* const gr0 = plan->get_boden_in_hoehe(i.z);
2547 i.z += welt->get_settings().get_way_height_clearance();
2548 grund_t* const gr = plan->get_boden_in_hoehe(i.z);
2549
2550 if(gr==NULL) {
2551 slope_t::type hang = gr0 ? gr0->get_grund_hang() : 0;
2552 // add new elevated ground
2553 monorailboden_t* const monorail = new monorailboden_t(i, hang);
2554 plan->boden_hinzufuegen(monorail);
2555 monorail->calc_image();
2556 }
2557 }
2558 }
2559
2560
2561
build_road()2562 void way_builder_t::build_road()
2563 {
2564 // only public player or cities (sp==NULL) can build cityroads with sidewalk
2565 bool add_sidewalk = build_sidewalk && (player_builder==NULL || player_builder->is_public_service());
2566
2567 if(add_sidewalk) {
2568 player_builder = NULL;
2569 }
2570
2571 // init undo
2572 if(player_builder!=NULL) {
2573 // intercity roads have no owner, so we must check for an owner
2574 player_builder->init_undo(road_wt,get_count());
2575 }
2576
2577 for( uint32 i=0; i<get_count(); i++ ) {
2578 if((i&3)==0) {
2579 INT_CHECK( "wegbauer 1584" );
2580 }
2581
2582 const koord k = route[i].get_2d();
2583 grund_t* gr = welt->lookup(route[i]);
2584 sint64 cost = 0;
2585
2586 bool extend = gr->weg_erweitern(road_wt, route.get_short_ribi(i));
2587
2588 // bridges/tunnels have their own track type and must not upgrade
2589 if(gr->get_typ()==grund_t::brueckenboden || gr->get_typ()==grund_t::tunnelboden) {
2590 continue;
2591 }
2592
2593 if(extend) {
2594 weg_t * weg = gr->get_weg(road_wt);
2595
2596 // keep faster ways or if it is the same way ... (@author prissi)
2597 if(weg->get_desc()==desc || keep_existing_ways || (keep_existing_city_roads && weg->hat_gehweg()) || (keep_existing_faster_ways && weg->get_desc()->get_topspeed()>desc->get_topspeed()) || (player_builder!=NULL && weg->is_deletable(player_builder)!=NULL) || (gr->get_typ()==grund_t::monorailboden && (bautyp&elevated_flag)==0)) {
2598 //nothing to be done
2599 //DBG_MESSAGE("way_builder_t::build_road()","nothing to do at (%i,%i)",k.x,k.y);
2600 }
2601 else {
2602 // we take ownership => we take care to maintain the roads completely ...
2603 player_t *s = weg->get_owner();
2604 player_t::add_maintenance(s, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
2605 // cost is the more expensive one, so downgrading is between removing and new building
2606 cost -= max( weg->get_desc()->get_price(), desc->get_price() );
2607 weg->set_desc(desc);
2608 // respect max speed of catenary
2609 wayobj_t const* const wo = gr->get_wayobj(desc->get_wtyp());
2610 if (wo && wo->get_desc()->get_topspeed() < weg->get_max_speed()) {
2611 weg->set_max_speed( wo->get_desc()->get_topspeed() );
2612 }
2613 weg->set_gehweg(add_sidewalk);
2614 player_t::add_maintenance( player_builder, weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
2615 weg->set_owner(player_builder);
2616 // respect speed limit of crossing
2617 weg->count_sign();
2618 }
2619 }
2620 else {
2621 // make new way
2622 strasse_t * str = new strasse_t();
2623
2624 str->set_desc(desc);
2625 str->set_gehweg(add_sidewalk);
2626 cost = -gr->neuen_weg_bauen(str, route.get_short_ribi(i), player_builder)-desc->get_price();
2627
2628 // prissi: into UNDO-list, so we can remove it later
2629 if(player_builder!=NULL) {
2630 // intercity roads have no owner, so we must check for an owner
2631 player_builder->add_undo( route[i] );
2632 }
2633 }
2634 gr->calc_image(); // because it may be a crossing ...
2635 minimap_t::get_instance()->calc_map_pixel(k);
2636 player_t::book_construction_costs(player_builder, cost, k, road_wt);
2637 } // for
2638 }
2639
2640
build_track()2641 void way_builder_t::build_track()
2642 {
2643 if(get_count() > 1) {
2644 // init undo
2645 player_builder->init_undo(desc->get_wtyp(), get_count());
2646
2647 // built tracks
2648 for( uint32 i=0; i<get_count(); i++ ) {
2649 sint64 cost = 0;
2650 grund_t* gr = welt->lookup(route[i]);
2651 ribi_t::ribi ribi = route.get_short_ribi(i);
2652
2653 if(gr->get_typ()==grund_t::wasser) {
2654 // not building on the sea ...
2655 continue;
2656 }
2657
2658 bool const extend = gr->weg_erweitern(desc->get_wtyp(), ribi);
2659
2660 // bridges/tunnels have their own track type and must not upgrade
2661 if((gr->get_typ()==grund_t::brueckenboden || gr->get_typ()==grund_t::tunnelboden) && gr->get_weg_nr(0)->get_waytype()==desc->get_wtyp()) {
2662 continue;
2663 }
2664
2665 if(extend) {
2666 weg_t* const weg = gr->get_weg(desc->get_wtyp());
2667 bool change_desc = true;
2668
2669 // do not touch fences, tram way etc. if there is already same way with different type
2670 // keep faster ways or if it is the same way ... (@author prissi)
2671 if (weg->get_desc() == desc ||
2672 (desc->get_styp() == 0 && weg->get_desc()->get_styp() == type_tram && gr->has_two_ways()) ||
2673 keep_existing_ways ||
2674 (keep_existing_faster_ways && weg->get_desc()->get_topspeed() > desc->get_topspeed()) ||
2675 (gr->get_typ() == grund_t::monorailboden && !(bautyp & elevated_flag) && gr->get_weg_nr(0)->get_waytype()==desc->get_wtyp())) {
2676 //nothing to be done
2677 change_desc = false;
2678 }
2679
2680 // build tram track over crossing -> remove crossing
2681 if( gr->has_two_ways() && desc->get_styp()==type_tram && weg->get_desc()->get_styp() != type_tram ) {
2682 if( crossing_t *cr = gr->find<crossing_t>(2) ) {
2683 // change to tram track
2684 cr->mark_image_dirty( cr->get_image(), 0);
2685 cr->cleanup(player_builder);
2686 delete cr;
2687 change_desc = true;
2688 // tell way we have no crossing any more, restore speed limit
2689 gr->get_weg_nr(0)->clear_crossing();
2690 gr->get_weg_nr(0)->set_desc( gr->get_weg_nr(0)->get_desc() );
2691 gr->get_weg_nr(1)->clear_crossing();
2692 }
2693 }
2694
2695 if( change_desc ) {
2696 // we take ownership => we take care to maintain the roads completely ...
2697 player_t *s = weg->get_owner();
2698 player_t::add_maintenance( s, -weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
2699 // cost is the more expensive one, so downgrading is between removing and new buidling
2700 cost -= max( weg->get_desc()->get_price(), desc->get_price() );
2701 weg->set_desc(desc);
2702 // respect max speed of catenary
2703 wayobj_t const* const wo = gr->get_wayobj(desc->get_wtyp());
2704 if (wo && wo->get_desc()->get_topspeed() < weg->get_max_speed()) {
2705 weg->set_max_speed( wo->get_desc()->get_topspeed() );
2706 }
2707 player_t::add_maintenance( player_builder, weg->get_desc()->get_maintenance(), weg->get_desc()->get_finance_waytype());
2708 weg->set_owner(player_builder);
2709 // respect speed limit of crossing
2710 weg->count_sign();
2711 }
2712 }
2713 else {
2714 weg_t* const sch = weg_t::alloc(desc->get_wtyp());
2715 sch->set_desc(desc);
2716
2717 cost = -gr->neuen_weg_bauen(sch, ribi, player_builder)-desc->get_price();
2718
2719 // connect canals to sea
2720 if( desc->get_wtyp() == water_wt ) {
2721 // do not connect across slopes
2722 ribi_t::ribi slope_ribi = ribi_t::all;
2723 if (gr->get_grund_hang()!=slope_t::flat) {
2724 slope_ribi = ribi_t::doubles( ribi_type(gr->get_weg_hang()) );
2725 }
2726
2727 for( int j = 0; j < 4; j++ ) {
2728 if (ribi_t::nsew[j] & slope_ribi) {
2729 grund_t *sea = NULL;
2730 if (gr->get_neighbour(sea, invalid_wt, ribi_t::nsew[j]) && sea->is_water() ) {
2731 gr->weg_erweitern( water_wt, ribi_t::nsew[j] );
2732 sea->calc_image();
2733 }
2734 }
2735 }
2736 }
2737
2738 // prissi: into UNDO-list, so we can remove it later
2739 player_builder->add_undo( route[i] );
2740 }
2741
2742 gr->calc_image();
2743 minimap_t::get_instance()->calc_map_pixel( gr->get_pos().get_2d() );
2744 player_t::book_construction_costs(player_builder, cost, gr->get_pos().get_2d(), desc->get_finance_waytype());
2745
2746 if((i&3)==0) {
2747 INT_CHECK( "wegbauer 1584" );
2748 }
2749 }
2750 }
2751 }
2752
2753
2754
build_powerline()2755 void way_builder_t::build_powerline()
2756 {
2757 if( get_count() < 1 ) {
2758 return;
2759 }
2760
2761 // no undo
2762 player_builder->init_undo(powerline_wt,get_count());
2763
2764 for( uint32 i=0; i<get_count(); i++ ) {
2765 grund_t* gr = welt->lookup(route[i]);
2766
2767 leitung_t* lt = gr->get_leitung();
2768 bool build_powerline = false;
2769 // ok, really no lt here ...
2770 if(lt==NULL) {
2771 if(gr->ist_natur()) {
2772 // remove trees etc.
2773 sint64 cost = gr->remove_trees();
2774 player_t::book_construction_costs(player_builder, -cost, gr->get_pos().get_2d(), powerline_wt);
2775 }
2776 lt = new leitung_t(route[i], player_builder );
2777 gr->obj_add(lt);
2778
2779 // prissi: into UNDO-list, so we can remove it later
2780 player_builder->add_undo( route[i] );
2781 build_powerline = true;
2782 }
2783 else {
2784 // modernize the network
2785 if( !keep_existing_faster_ways || lt->get_desc()->get_topspeed() < desc->get_topspeed() ) {
2786 build_powerline = true;
2787 player_t::add_maintenance( lt->get_owner(), -lt->get_desc()->get_maintenance(), powerline_wt );
2788 }
2789 }
2790 if (build_powerline) {
2791 lt->set_desc(desc);
2792 player_t::book_construction_costs(player_builder, -desc->get_price(), gr->get_pos().get_2d(), powerline_wt);
2793 // this adds maintenance
2794 lt->leitung_t::finish_rd();
2795 minimap_t::get_instance()->calc_map_pixel( gr->get_pos().get_2d() );
2796 }
2797
2798 if((i&3)==0) {
2799 INT_CHECK( "wegbauer 1584" );
2800 }
2801 }
2802 }
2803
2804
2805
2806 // this can drive any river, even a river that has max_speed=0
2807 class fluss_test_driver_t : public test_driver_t
2808 {
check_next_tile(const grund_t * gr) const2809 bool check_next_tile(const grund_t* gr) const OVERRIDE { return gr->get_weg_ribi_unmasked(water_wt)!=0; }
get_ribi(const grund_t * gr) const2810 ribi_t::ribi get_ribi(const grund_t* gr) const OVERRIDE { return gr->get_weg_ribi_unmasked(water_wt); }
get_waytype() const2811 waytype_t get_waytype() const OVERRIDE { return invalid_wt; }
get_cost(const grund_t *,const weg_t *,const sint32,ribi_t::ribi) const2812 int get_cost(const grund_t *, const weg_t *, const sint32, ribi_t::ribi) const OVERRIDE { return 1; }
is_target(const grund_t * cur,const grund_t *) const2813 bool is_target(const grund_t *cur,const grund_t *) const OVERRIDE { return cur->is_water() && cur->get_grund_hang()==slope_t::flat; }
2814 };
2815
2816
2817 // make a river
build_river()2818 void way_builder_t::build_river()
2819 {
2820 /* since the constraints of the wayfinder ensures that a river flows always downwards
2821 * we can assume that the first tiles are the ocean.
2822 * Usually the wayfinder would find either direction!
2823 * route.front() tile at the ocean, route.back() the spring of the river
2824 */
2825
2826 // Do we join an other river?
2827 uint32 start_n = 0;
2828 for( uint32 idx=start_n; idx<get_count(); idx++ ) {
2829 if( welt->lookup(route[idx])->hat_weg(water_wt) || welt->lookup(route[idx])->get_hoehe() == welt->get_water_hgt(route[idx].get_2d()) ) {
2830 start_n = idx;
2831 }
2832 }
2833 if( start_n == get_count()-1 ) {
2834 // completely joined another river => nothing to do
2835 return;
2836 }
2837
2838 // first check then lower riverbed
2839 const sint8 start_h = route[start_n].z;
2840 uint32 end_n = get_count();
2841 uint32 i = start_n;
2842 while(i<get_count()) {
2843 // first find all tiles that are on the same level as tile i
2844 // and check whether we can lower all of them
2845 // if lowering fails we do not continue river building
2846 bool ok = true;
2847 uint32 j;
2848 for(j=i; j<get_count() && ok; j++) {
2849 // one step higher?
2850 if (route[j].z > route[i].z) break;
2851 // check
2852 ok = welt->can_flatten_tile(NULL, route[j].get_2d(), max(route[j].z-1, start_h));
2853 }
2854 // now lower all tiles that have the same height as tile i
2855 for(uint32 k=i; k<j; k++) {
2856 welt->flatten_tile(NULL, route[k].get_2d(), max(route[k].z-1, start_h));
2857 }
2858 if (!ok) {
2859 end_n = j;
2860 break;
2861 }
2862 i = j;
2863 }
2864 // nothing to built ?
2865 if (start_n >= end_n-1) {
2866 return;
2867 }
2868
2869 // now build the river
2870 grund_t *gr_first = NULL;
2871 for( uint32 i=start_n; i<end_n; i++ ) {
2872 grund_t* gr = welt->lookup_kartenboden(route[i].get_2d());
2873 if( gr_first == NULL) {
2874 gr_first = gr;
2875 }
2876 if( gr->get_typ()!=grund_t::wasser ) {
2877 // get direction
2878 ribi_t::ribi ribi = i<end_n-1 ? route.get_short_ribi(i) : ribi_type(route[i-1]-route[i]);
2879 bool extend = gr->weg_erweitern(water_wt, ribi);
2880 if( !extend ) {
2881 weg_t *sch=weg_t::alloc(water_wt);
2882 sch->set_desc(desc);
2883 gr->neuen_weg_bauen(sch, ribi, NULL);
2884 }
2885 }
2886 }
2887 gr_first->calc_image(); // to calculate ribi of water tiles
2888
2889 // we will make rivers gradually larger by stepping up their width
2890 if( env_t::river_types>1 && start_n<get_count()) {
2891 /* since we will stop at the first crossing with an existent river,
2892 * we cannot make sure, we have the same destination;
2893 * thus we use the routefinder to find the sea
2894 */
2895 route_t to_the_sea;
2896 fluss_test_driver_t river_tester;
2897 if (to_the_sea.find_route(welt, welt->lookup_kartenboden(route[start_n].get_2d())->get_pos(), &river_tester, 0, ribi_t::all, 0x7FFFFFFF)) {
2898 FOR(koord3d_vector_t, const& i, to_the_sea.get_route()) {
2899 if (weg_t* const w = welt->lookup(i)->get_weg(water_wt)) {
2900 int type;
2901 for( type=env_t::river_types-1; type>0; type-- ) {
2902 // lookup type
2903 if( w->get_desc()==desc_table.get(env_t::river_type[type]) ) {
2904 break;
2905 }
2906 }
2907 // still room to expand
2908 if( type>0 ) {
2909 // thus we enlarge
2910 w->set_desc( desc_table.get(env_t::river_type[type-1]) );
2911 w->calc_image();
2912 }
2913 }
2914 }
2915 }
2916 }
2917 }
2918
2919
2920
build()2921 void way_builder_t::build()
2922 {
2923 if(get_count()<2 || get_count() > maximum) {
2924 DBG_MESSAGE("way_builder_t::build()","called, but no valid route.");
2925 // no valid route here ...
2926 return;
2927 }
2928 DBG_MESSAGE("way_builder_t::build()", "type=%d max_n=%d start=%d,%d end=%d,%d", bautyp, get_count() - 1, route.front().x, route.front().y, route.back().x, route.back().y);
2929
2930 #ifdef DEBUG_ROUTES
2931 uint32 ms = dr_time();
2932 #endif
2933
2934 if ( (bautyp&terraform_flag)!=0 && (bautyp&(tunnel_flag|elevated_flag))==0 && bautyp!=river) {
2935 // do the terraforming
2936 do_terraforming();
2937 }
2938 // first add all new underground tiles ... (and finished if successful)
2939 if(bautyp&tunnel_flag) {
2940 build_tunnel_tile();
2941 return;
2942 }
2943
2944 // add elevated ground for elevated tracks
2945 if(bautyp&elevated_flag) {
2946 build_elevated();
2947 }
2948
2949
2950 INT_CHECK("simbau 1072");
2951 switch(bautyp&bautyp_mask) {
2952 case wasser:
2953 case schiene:
2954 case schiene_tram: // Dario: Tramway
2955 case monorail:
2956 case maglev:
2957 case narrowgauge:
2958 case luft:
2959 DBG_MESSAGE("way_builder_t::build", "schiene");
2960 build_track();
2961 break;
2962 case strasse:
2963 build_road();
2964 DBG_MESSAGE("way_builder_t::build", "strasse");
2965 break;
2966 case leitung:
2967 build_powerline();
2968 break;
2969 case river:
2970 build_river();
2971 break;
2972 default:
2973 break;
2974 }
2975
2976 INT_CHECK("simbau 1087");
2977 build_tunnel_and_bridges();
2978
2979 INT_CHECK("simbau 1087");
2980
2981 #ifdef DEBUG_ROUTES
2982 DBG_MESSAGE("way_builder_t::build", "took %u ms", dr_time() - ms );
2983 #endif
2984 }
2985
2986
2987
2988 /*
2989 * This function calculates the distance of pos to the cuboid
2990 * spanned up by mini and maxi.
2991 * The result is already weighted according to
2992 * welt->get_settings().get_way_count_{straight,slope}().
2993 */
calc_distance(const koord3d & pos,const koord3d & mini,const koord3d & maxi)2994 uint32 way_builder_t::calc_distance( const koord3d &pos, const koord3d &mini, const koord3d &maxi )
2995 {
2996 uint32 dist = 0;
2997 if( pos.x < mini.x ) {
2998 dist += mini.x - pos.x;
2999 } else if( pos.x > maxi.x ) {
3000 dist += pos.x - maxi.x;
3001 }
3002 if( pos.y < mini.y ) {
3003 dist += mini.y - pos.y;
3004 } else if( pos.y > maxi.y ) {
3005 dist += pos.y - maxi.y;
3006 }
3007 settings_t const& s = welt->get_settings();
3008 dist *= s.way_count_straight;
3009 if( pos.z < mini.z ) {
3010 dist += (mini.z - pos.z) * s.way_count_slope;
3011 } else if( pos.z > maxi.z ) {
3012 dist += (pos.z - maxi.z) * s.way_count_slope;
3013 }
3014 return dist;
3015 }
3016