1 /*
2 * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
3 *
4 * This file is part of the Simutrans project under the artistic license.
5 * (see license.txt)
6 */
7
8 #include "simdebug.h"
9 #include "simobj.h"
10 #include "simfab.h"
11 #include "display/simgraph.h"
12 #include "simmenu.h"
13 #include "simplan.h"
14 #include "simworld.h"
15 #include "simhalt.h"
16 #include "player/simplay.h"
17 #include "simconst.h"
18 #include "macros.h"
19 #include "descriptor/ground_desc.h"
20 #include "boden/grund.h"
21 #include "boden/boden.h"
22 #include "boden/fundament.h"
23 #include "boden/wasser.h"
24 #include "boden/tunnelboden.h"
25 #include "boden/brueckenboden.h"
26 #include "boden/monorailboden.h"
27
28 #include "obj/gebaeude.h"
29
30 #include "dataobj/loadsave.h"
31 #include "dataobj/environment.h"
32
33 #include "gui/minimap.h"
34
35
36 karte_ptr_t planquadrat_t::welt;
37
38
swap(planquadrat_t & a,planquadrat_t & b)39 void swap(planquadrat_t& a, planquadrat_t& b)
40 {
41 sim::swap(a.halt_list, b.halt_list);
42 sim::swap(a.ground_size, b.ground_size);
43 sim::swap(a.halt_list_count, b.halt_list_count);
44 sim::swap(a.data, b.data);
45 sim::swap(a.climate_data, b.climate_data);
46 }
47
48 // deletes also all grounds in this array!
~planquadrat_t()49 planquadrat_t::~planquadrat_t()
50 {
51 if(ground_size==0) {
52 // empty
53 }
54 else if(ground_size==1) {
55 delete data.one;
56 }
57 else {
58 while(ground_size>0) {
59 ground_size --;
60 delete data.some[ground_size];
61 data.some[ground_size] = 0;
62 }
63 delete [] data.some;
64 }
65 delete [] halt_list;
66 halt_list_count = 0;
67 // to avoid access to this tile
68 ground_size = 0;
69 data.one = NULL;
70 }
71
72
get_boden_von_obj(obj_t * obj) const73 grund_t *planquadrat_t::get_boden_von_obj(obj_t *obj) const
74 {
75 if(ground_size==1) {
76 if(data.one && data.one->obj_ist_da(obj)) {
77 return data.one;
78 }
79 }
80 else {
81 for(uint8 i=0; i<ground_size; i++) {
82 if(data.some[i]->obj_ist_da(obj)) {
83 return data.some[i];
84 }
85 }
86 }
87 return NULL;
88 }
89
90
boden_hinzufuegen(grund_t * bd)91 void planquadrat_t::boden_hinzufuegen(grund_t *bd)
92 {
93 assert(!bd->ist_karten_boden());
94 if(ground_size==0) {
95 // completely empty
96 data.one = bd;
97 ground_size = 1;
98 minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d());
99 return;
100 }
101 else if(ground_size==1) {
102 // needs to convert to array
103 // assert(data.one->get_hoehe()!=bd->get_hoehe());
104 if(data.one->get_hoehe()==bd->get_hoehe()) {
105 DBG_MESSAGE("planquadrat_t::boden_hinzufuegen()","addition ground %s at (%i,%i,%i) will be ignored!",bd->get_name(),bd->get_pos().x,bd->get_pos().y,bd->get_pos().z);
106 return;
107 }
108 grund_t **tmp = new grund_t *[2];
109 tmp[0] = data.one;
110 tmp[1] = bd;
111 data.some = tmp;
112 ground_size = 2;
113 minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d());
114 return;
115 }
116 else {
117 // insert into array
118 uint8 i;
119 for(i=1; i<ground_size; i++) {
120 if(data.some[i]->get_hoehe()>=bd->get_hoehe()) {
121 break;
122 }
123 }
124 if(i<ground_size && data.some[i]->get_hoehe()==bd->get_hoehe()) {
125 DBG_MESSAGE("planquadrat_t::boden_hinzufuegen()","addition ground %s at (%i,%i,%i) will be ignored!",bd->get_name(),bd->get_pos().x,bd->get_pos().y,bd->get_pos().z);
126 return;
127 }
128 bd->set_kartenboden(false);
129 // extend array if needed
130 grund_t **tmp = new grund_t *[ground_size+1];
131 for( uint8 j=0; j<i; j++ ) {
132 tmp[j] = data.some[j];
133 }
134 tmp[i] = bd;
135 while(i<ground_size) {
136 tmp[i+1] = data.some[i];
137 i++;
138 }
139 ground_size ++;
140 delete [] data.some;
141 data.some = tmp;
142 minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d());
143 }
144 }
145
146
boden_entfernen(grund_t * bd)147 bool planquadrat_t::boden_entfernen(grund_t *bd)
148 {
149 assert(!bd->ist_karten_boden() && ground_size>0);
150 if(ground_size==1) {
151 ground_size = 0;
152 data.one = NULL;
153 return true;
154 }
155 else {
156 for(uint8 i=0; i<ground_size; i++) {
157 if(data.some[i]==bd) {
158 // found
159 while(i<ground_size-1) {
160 data.some[i] = data.some[i+1];
161 i++;
162 }
163 ground_size --;
164 // below 2?
165 if(ground_size==1) {
166 grund_t *tmp=data.some[0];
167 delete [] data.some;
168 data.one = tmp;
169 }
170 return true;
171 }
172 }
173 }
174 assert(0);
175 return false;
176 }
177
178
kartenboden_setzen(grund_t * bd,bool startup)179 void planquadrat_t::kartenboden_setzen(grund_t *bd, bool startup)
180 {
181 assert(bd);
182 grund_t *tmp = get_kartenboden();
183 if(tmp) {
184 boden_ersetzen(tmp,bd);
185 }
186 else {
187 data.one = bd;
188 ground_size = 1;
189 bd->set_kartenboden(true);
190 }
191 if (!startup) {
192 // water tiles need neighbor tiles, which might not be initialized at startup
193 bd->calc_image();
194 }
195 minimap_t::get_instance()->calc_map_pixel(bd->get_pos().get_2d());
196 }
197
198
199 /**
200 * replaces the map solid ground (or water) and deletes the old one
201 * @author Hansj�rg Malthaner
202 */
boden_ersetzen(grund_t * alt,grund_t * neu)203 void planquadrat_t::boden_ersetzen(grund_t *alt, grund_t *neu)
204 {
205 assert(alt!=NULL && neu!=NULL && !alt->is_halt() );
206
207 if(ground_size<=1) {
208 assert(data.one==alt || ground_size==0);
209 data.one = neu;
210 ground_size = 1;
211 neu->set_kartenboden(true);
212 }
213 else {
214 for(uint8 i=0; i<ground_size; i++) {
215 if(data.some[i]==alt) {
216 data.some[i] = neu;
217 neu->set_kartenboden(i==0);
218 break;
219 }
220 }
221 }
222 // transfer text and delete
223 if(alt) {
224 if(alt->get_flag(grund_t::has_text)) {
225 neu->set_flag(grund_t::has_text);
226 alt->clear_flag(grund_t::has_text);
227 }
228 // transfer all objects
229 while( alt->get_top()>0 ) {
230 neu->obj_add( alt->obj_remove_top() );
231 }
232 delete alt;
233 }
234 }
235
236
rdwr(loadsave_t * file,koord pos)237 void planquadrat_t::rdwr(loadsave_t *file, koord pos )
238 {
239 xml_tag_t p( file, "planquadrat_t" );
240
241 if(file->is_saving()) {
242 if(ground_size==1) {
243 file->wr_obj_id(data.one->get_typ());
244 data.one->rdwr(file);
245 }
246 else {
247 for(int i=0; i<ground_size; i++) {
248 file->wr_obj_id(data.some[i]->get_typ());
249 data.some[i]->rdwr(file);
250 }
251 }
252 file->wr_obj_id(-1);
253 }
254 else {
255 grund_t *gr;
256 sint8 hgt = welt->get_groundwater();
257 //DBG_DEBUG("planquadrat_t::rdwr()","Reading boden");
258 do {
259 short gtyp = file->rd_obj_id();
260
261 switch(gtyp) {
262 case -1: gr = NULL; break;
263 case grund_t::boden: gr = new boden_t(file, pos); break;
264 case grund_t::wasser: gr = new wasser_t(file, pos); break;
265 case grund_t::fundament: gr = new fundament_t(file, pos); break;
266 case grund_t::tunnelboden: gr = new tunnelboden_t(file, pos); break;
267 case grund_t::brueckenboden: gr = new brueckenboden_t(file, pos); break;
268 case grund_t::monorailboden: gr = new monorailboden_t(file, pos); break;
269 default:
270 gr = 0; // Hajo: keep compiler happy, fatal() never returns
271 dbg->fatal("planquadrat_t::rdwr()","Error while loading game: Unknown ground type '%d'",gtyp);
272 }
273 // check if we have a matching building here, otherwise set to nothing
274 if (gr && gtyp == grund_t::fundament && gr->find<gebaeude_t>() == NULL) {
275 koord3d pos = gr->get_pos();
276 // show normal ground here
277 grund_t *neu = new boden_t(pos, 0);
278 if(gr->get_flag(grund_t::has_text)) {
279 neu->set_flag(grund_t::has_text);
280 gr->clear_flag(grund_t::has_text);
281 }
282 // transfer all objects
283 while( gr->get_top()>0 ) {
284 neu->obj_add( gr->obj_remove_top() );
285 }
286 delete gr;
287 gr = neu;
288 //DBG_MESSAGE("planquadrat_t::rwdr", "unknown building (or prepare for factory) at %d,%d replaced by normal ground!", pos.x,pos.y);
289 }
290 // we should also check for ground below factories
291 if(gr) {
292 if(ground_size==0) {
293 data.one = gr;
294 ground_size = 1;
295 gr->set_kartenboden(true);
296 hgt = welt->lookup_hgt(pos);
297 }
298 else {
299 // other ground must not reset the height
300 boden_hinzufuegen(gr);
301 welt->set_grid_hgt( pos, hgt );
302 }
303 }
304 } while(gr != 0);
305 }
306 }
307
308
check_season_snowline(const bool season_change,const bool snowline_change)309 void planquadrat_t::check_season_snowline(const bool season_change, const bool snowline_change)
310 {
311 if( ground_size == 1 ) {
312 data.one->check_season_snowline( season_change, snowline_change );
313 }
314 else if( ground_size > 1 ) {
315 for( uint8 i = 0; i < ground_size; i++ ) {
316 data.some[i]->check_season_snowline( season_change, snowline_change );
317 }
318 }
319 }
320
321
correct_water()322 void planquadrat_t::correct_water()
323 {
324 grund_t *gr = get_kartenboden();
325 slope_t::type slope = gr->get_grund_hang();
326 sint8 max_height = gr->get_hoehe() + slope_t::max_diff( slope );
327 koord k = gr->get_pos().get_2d();
328 sint8 water_hgt = welt->get_water_hgt(k);
329 if( gr && gr->get_typ() != grund_t::wasser && max_height <= water_hgt ) {
330 // below water but ground => convert
331 kartenboden_setzen( new wasser_t(koord3d( k, water_hgt ) ) );
332 }
333 else if( gr && gr->get_typ() == grund_t::wasser && max_height > water_hgt ) {
334 // water above ground => to ground
335 kartenboden_setzen( new boden_t(gr->get_pos(), gr->get_disp_slope() ) );
336 }
337 else if( gr && gr->get_typ() == grund_t::wasser && gr->get_hoehe() != water_hgt ) {
338 // water at wrong height
339 gr->set_hoehe( water_hgt );
340 }
341
342 gr = get_kartenboden();
343 if( gr && gr->get_typ() != grund_t::wasser && gr->get_disp_height() < water_hgt && welt->max_hgt(k) > water_hgt ) {
344 sint8 disp_hneu = water_hgt;
345 sint8 disp_hn_sw = max( gr->get_hoehe() + corner_sw(slope), water_hgt );
346 sint8 disp_hn_se = max( gr->get_hoehe() + corner_se(slope), water_hgt );
347 sint8 disp_hn_ne = max( gr->get_hoehe() + corner_ne(slope), water_hgt );
348 sint8 disp_hn_nw = max( gr->get_hoehe() + corner_nw(slope), water_hgt );
349 const uint8 sneu = (disp_hn_sw - disp_hneu) + ((disp_hn_se - disp_hneu) * 3) + ((disp_hn_ne - disp_hneu) * 9) + ((disp_hn_nw - disp_hneu) * 27);
350 gr->set_hoehe( disp_hneu );
351 gr->set_grund_hang( (slope_t::type)sneu );
352 }
353 }
354
355
abgesenkt()356 void planquadrat_t::abgesenkt()
357 {
358 grund_t *gr = get_kartenboden();
359 if(gr) {
360 const uint8 slope = gr->get_grund_hang();
361
362 gr->obj_loesche_alle(NULL);
363 sint8 max_hgt = gr->get_hoehe() + (slope != 0 ? (slope & 7 ? 1 : 2) : 0);
364
365 koord k(gr->get_pos().get_2d());
366 if( max_hgt <= welt->get_water_hgt( k ) && gr->get_typ() != grund_t::wasser ) {
367 gr = new wasser_t(gr->get_pos());
368 kartenboden_setzen( gr );
369 // recalc water ribis of neighbors
370 for(int r=0; r<4; r++) {
371 grund_t *gr2 = welt->lookup_kartenboden(k + koord::nsew[r]);
372 if (gr2 && gr2->is_water()) {
373 gr2->calc_image();
374 }
375 }
376 }
377 else {
378 minimap_t::get_instance()->calc_map_pixel(k);
379 }
380 gr->set_grund_hang( slope );
381 }
382 }
383
384
angehoben()385 void planquadrat_t::angehoben()
386 {
387 grund_t *gr = get_kartenboden();
388 if(gr) {
389 const uint8 slope = gr->get_grund_hang();
390
391 gr->obj_loesche_alle(NULL);
392 sint8 max_hgt = gr->get_hoehe() + (slope != 0 ? (slope & 7 ? 1 : 2) : 0);
393
394 koord k(gr->get_pos().get_2d());
395 if( max_hgt > welt->get_water_hgt( k ) && gr->get_typ() == grund_t::wasser ) {
396 gr = new boden_t(gr->get_pos(), slope );
397 kartenboden_setzen( gr );
398 // recalc water ribis
399 for(int r=0; r<4; r++) {
400 grund_t *gr2 = welt->lookup_kartenboden(k + koord::nsew[r]);
401 if( gr2 && gr2->is_water() ) {
402 gr2->calc_image();
403 }
404 }
405 }
406 else if( slope == 0 && gr->get_hoehe() == welt->get_water_hgt(k) && gr->get_typ() == grund_t::wasser ) {
407 // water at zero level => make it land
408 gr = new boden_t(gr->get_pos(), slope );
409 kartenboden_setzen( gr );
410 // recalc water ribis
411 for(int r=0; r<4; r++) {
412 grund_t *gr2 = welt->lookup_kartenboden(k + koord::nsew[r]);
413 if( gr2 && gr2->is_water() ) {
414 gr2->calc_image();
415 }
416 }
417 }
418 else {
419 minimap_t::get_instance()->calc_map_pixel(k);
420 }
421 }
422 }
423
424
display_obj(const sint16 xpos,const sint16 ypos,const sint16 raster_tile_width,bool is_global,const sint8 hmin,const sint8 hmax CLIP_NUM_DEF) const425 void planquadrat_t::display_obj(const sint16 xpos, const sint16 ypos, const sint16 raster_tile_width, bool is_global, const sint8 hmin, const sint8 hmax CLIP_NUM_DEF) const
426 {
427 grund_t *gr0 = get_kartenboden();
428 if( gr0->get_flag( grund_t::dirty ) ) {
429 gr0->set_all_obj_dirty(); // prevent artifacts with smart hide cursor
430 }
431
432 const sint8 h0 = gr0->get_disp_height();
433 uint8 i = 1;
434 // underground
435 if( hmin < h0 ) {
436 for( ; i < ground_size; i++ ) {
437 const grund_t* gr = data.some[i];
438 const sint8 h = gr->get_hoehe();
439 const slope_t::type slope = gr->get_grund_hang();
440 const sint8 htop = h + max(max(corner_sw(slope), corner_se(slope)),max(corner_ne(slope), corner_nw(slope)));
441 // above ground
442 if( h > h0 ) {
443 break;
444 }
445 // not too low?
446 if( htop >= hmin ) {
447 const sint16 yypos = ypos - tile_raster_scale_y( (h - h0) * TILE_HEIGHT_STEP, raster_tile_width );
448
449 gr->display_boden( xpos, yypos, raster_tile_width CLIP_NUM_PAR );
450 gr->display_obj_all( xpos, yypos, raster_tile_width, is_global CLIP_NUM_PAR );
451 }
452 }
453 }
454 //const bool kartenboden_dirty = gr->get_flag(grund_t::dirty);
455 if( gr0->get_flag( grund_t::draw_as_obj ) || !gr0->is_karten_boden_visible() ) {
456 gr0->display_boden( xpos, ypos, raster_tile_width CLIP_NUM_PAR );
457 }
458
459 if( env_t::simple_drawing ) {
460 // ignore trees going though bridges
461 gr0->display_obj_all_quick_and_dirty( xpos, ypos, raster_tile_width, is_global CLIP_NUM_PAR );
462 }
463 else {
464 // clip everything at the next tile above
465 if( i < ground_size ) {
466
467 clip_dimension p_cr = display_get_clip_wh( CLIP_NUM_VAR );
468
469 for( uint8 j = i; j < ground_size; j++ ) {
470 const sint8 h = data.some[j]->get_hoehe();
471 const sint8 htop = h + slope_t::max_diff(data.some[j]->get_grund_hang());
472 // too high?
473 if( h > hmax ) {
474 break;
475 }
476 // not too low?
477 if( htop >= hmin ) {
478 // something on top: clip horizontally to prevent trees etc shining trough bridges
479 const sint16 yh = ypos - tile_raster_scale_y( (h - h0) * TILE_HEIGHT_STEP, raster_tile_width ) + ((3 * raster_tile_width) >> 2);
480 if( yh >= p_cr.y ) {
481 display_push_clip_wh(p_cr.x, yh, p_cr.w, p_cr.h + p_cr.y - yh CLIP_NUM_PAR );
482 }
483 break;
484 }
485 }
486 gr0->display_obj_all( xpos, ypos, raster_tile_width, is_global CLIP_NUM_PAR );
487 display_pop_clip_wh(CLIP_NUM_VAR);
488 }
489 else {
490 gr0->display_obj_all( xpos, ypos, raster_tile_width, is_global CLIP_NUM_PAR );
491 }
492 }
493 // above ground
494 for( ; i < ground_size; i++ ) {
495 const grund_t* gr = data.some[i];
496 const sint8 h = gr->get_hoehe();
497 const slope_t::type slope = gr->get_grund_hang();
498 const sint8 htop = h + max(max(corner_sw(slope), corner_se(slope)),max(corner_ne(slope), corner_nw(slope)));
499 // too high?
500 if( h > hmax ) {
501 break;
502 }
503 // not too low?
504 if( htop >= hmin ) {
505 const sint16 yypos = ypos - tile_raster_scale_y( (h - h0) * TILE_HEIGHT_STEP, raster_tile_width );
506 gr->display_boden( xpos, yypos, raster_tile_width CLIP_NUM_PAR );
507 gr->display_obj_all( xpos, yypos, raster_tile_width, is_global CLIP_NUM_PAR );
508 }
509 }
510 }
511
512
overlay_img(grund_t * gr)513 image_id overlay_img(grund_t *gr)
514 {
515 // only transparent outline
516 image_id img;
517 if( gr->get_typ()==grund_t::wasser ) {
518 // water is always flat and does not return proper image_id
519 img = ground_desc_t::outside->get_image(0);
520 }
521 else {
522 img = gr->get_image();
523 if( img==IMG_EMPTY ) {
524 // foundations or underground mode
525 img = ground_desc_t::get_ground_tile( gr );
526 }
527 }
528 return img;
529 }
530
531
display_overlay(const sint16 xpos,const sint16 ypos) const532 void planquadrat_t::display_overlay(const sint16 xpos, const sint16 ypos) const
533 {
534 grund_t *gr=get_kartenboden();
535
536 // building transformers - show outlines of factories
537
538 /* alternative method of finding selected tool - may be more useful in future but use simpler method for now
539 tool_t *tool = welt->get_tool(welt->get_active_player_nr());
540 int tool_id = tool->get_id();
541
542 if(tool_id==(TOOL_TRANSFORMER|GENERAL_TOOL).... */
543
544 if( (grund_t::underground_mode == grund_t::ugm_all
545 || (grund_t::underground_mode == grund_t::ugm_level && gr->get_hoehe() == grund_t::underground_level + welt->get_settings().get_way_height_clearance()) )
546 && gr->get_typ()==grund_t::fundament
547 && tool_t::general_tool[TOOL_TRANSFORMER]->is_selected()) {
548 gebaeude_t *gb = gr->find<gebaeude_t>();
549 if(gb) {
550 fabrik_t* fab=gb->get_fabrik();
551 if(fab) {
552 FLAGGED_PIXVAL status = color_idx_to_rgb(COL_RED);
553 if(fab->get_desc()->is_electricity_producer()) {
554 status = color_idx_to_rgb(COL_LIGHT_BLUE);
555 if(fab->is_transformer_connected()) {
556 status = color_idx_to_rgb(COL_LIGHT_TURQUOISE);
557 }
558 }
559 else {
560 if(fab->is_transformer_connected()) {
561 status = color_idx_to_rgb(COL_ORANGE);
562 }
563 if(fab->get_prodfactor_electric()>0) {
564 status = color_idx_to_rgb(COL_GREEN);
565 }
566 }
567 display_img_blend( overlay_img(gr), xpos, ypos, status | OUTLINE_FLAG | TRANSPARENT50_FLAG, 0, true);
568 }
569 }
570 }
571
572 // display station owner boxes
573 if(env_t::station_coverage_show && halt_list_count>0) {
574
575 if(env_t::use_transparency_station_coverage) {
576
577 // only transparent outline
578 image_id img = overlay_img(gr);
579
580 for(int halt_count = 0; halt_count < halt_list_count; halt_count++) {
581 const FLAGGED_PIXVAL transparent = PLAYER_FLAG | OUTLINE_FLAG | color_idx_to_rgb(halt_list[halt_count]->get_owner()->get_player_color1() + 4);
582 display_img_blend( img, xpos, ypos, transparent | TRANSPARENT25_FLAG, 0, 0);
583 }
584 /*
585 // unfortunately, too expensive for display
586 // plot player outline colours - we always plot in order of players so that the order of the stations in halt_list
587 // doesn't affect the colour displayed [since blend(col1,blend(col2,screen)) != blend(col2,blend(col1,screen))]
588 for(int player_count = 0; player_count<MAX_PLAYER_COUNT; player_count++) {
589 player_t *display_player = welt->get_player(player_count);
590 const FLAGGED_PIXVAL transparent = PLAYER_FLAG | OUTLINE_FLAG | color_idx_to_rgb(display_player->get_player_color1() * 4 + 4);
591 for(int halt_count = 0; halt_count < halt_list_count; halt_count++) {
592 if(halt_list[halt_count]->get_owner() == display_player) {
593 display_img_blend( img, xpos, ypos, transparent | TRANSPARENT25_FLAG, 0, 0);
594 }
595 }
596 }
597 */
598 }
599 else {
600 const sint16 raster_tile_width = get_tile_raster_width();
601 // opaque boxes (
602 const sint16 r=raster_tile_width/8;
603 const sint16 x=xpos+raster_tile_width/2-r;
604 const sint16 y=ypos+(raster_tile_width*3)/4-r - (gr->get_grund_hang()? tile_raster_scale_y(8,raster_tile_width): 0);
605 const bool kartenboden_dirty = gr->get_flag(grund_t::dirty);
606 const sint16 off = (raster_tile_width>>5);
607 // suitable start search
608 for (size_t h = halt_list_count; h-- != 0;) {
609 display_fillbox_wh_clip_rgb(x - h * off, y + h * off, r, r, PLAYER_FLAG | color_idx_to_rgb(halt_list[h]->get_owner()->get_player_color1() + 4), kartenboden_dirty);
610 }
611 }
612 }
613
614 gr->display_overlay( xpos, ypos );
615 if( ground_size > 1 ) {
616 const sint8 h0 = gr->get_disp_height();
617 for( uint8 i = 1; i < ground_size; i++ ) {
618 grund_t* gr = data.some[i];
619 const sint8 h = gr->get_disp_height();
620 const sint16 yypos = ypos - (h - h0 ) * get_tile_raster_width() / 2;
621 gr->display_overlay( xpos, yypos );
622 }
623 }
624 }
625
626 /**
627 * Finds halt belonging to a player
628 * @param player owner of the halts we are interested in.
629 */
get_halt(player_t * player) const630 halthandle_t planquadrat_t::get_halt(player_t *player) const
631 {
632 for( uint8 i=0; i < get_boden_count(); i++ ) {
633 halthandle_t my_halt = get_boden_bei(i)->get_halt();
634 if( my_halt.is_bound() && (player == NULL || player == my_halt->get_owner()) ) {
635 return my_halt;
636 }
637 }
638 return halthandle_t();
639 }
640
641
642 // these functions are private helper functions for halt_list
halt_list_remove(halthandle_t halt)643 void planquadrat_t::halt_list_remove( halthandle_t halt )
644 {
645 for( uint8 i=0; i<halt_list_count; i++ ) {
646 if(halt_list[i]==halt) {
647 for( uint8 j=i+1; j<halt_list_count; j++ ) {
648 halt_list[j-1] = halt_list[j];
649 }
650 halt_list_count--;
651 break;
652 }
653 }
654 }
655
656
halt_list_insert_at(halthandle_t halt,uint8 pos)657 void planquadrat_t::halt_list_insert_at( halthandle_t halt, uint8 pos )
658 {
659 // extend list?
660 if((halt_list_count%4)==0) {
661 halthandle_t *tmp = new halthandle_t[halt_list_count+4];
662 if(halt_list!=NULL) {
663 // now insert
664 for( uint8 i=0; i<halt_list_count; i++ ) {
665 tmp[i] = halt_list[i];
666 }
667 delete [] halt_list;
668 }
669 halt_list = tmp;
670 }
671 // now insert
672 for( uint8 i=halt_list_count; i>pos; i-- ) {
673 halt_list[i] = halt_list[i-1];
674 }
675 halt_list[pos] = halt;
676 halt_list_count ++;
677 }
678
679
680 /* The following functions takes at least 8 bytes of memory per tile but speed up passenger generation *
681 * @author prissi
682 */
add_to_haltlist(halthandle_t halt,bool unsorted)683 void planquadrat_t::add_to_haltlist(halthandle_t halt, bool unsorted)
684 {
685 if(halt.is_bound()) {
686 if (!unsorted) {
687 // quick and dirty way to our 2d koodinates ...
688 const koord pos = get_kartenboden()->get_pos().get_2d();
689
690 if( halt_list_count > 0 ) {
691
692 // since only the first one gets all, we want the closest halt one to be first
693 halt_list_remove(halt);
694 uint32 dist = koord_distance(halt->get_next_pos(pos), pos);
695 for(unsigned insert_pos=0; insert_pos<halt_list_count; insert_pos++) {
696
697 if( koord_distance(halt_list[insert_pos]->get_next_pos(pos), pos) > dist ) {
698 halt_list_insert_at( halt, insert_pos );
699 return;
700 }
701 }
702 // not found
703 }
704 // first just or just append to the end ...
705 halt_list_insert_at( halt, halt_list_count );
706 }
707 else {
708 // insert only if not already present
709 for(uint8 i = 0; i<halt_list_count; i++) {
710 if (halt_list[i] == halt) {
711 return; // already inserted
712 }
713 }
714 halt_list_insert_at( halt, halt_list_count );
715 }
716 }
717 }
718
719 /**
720 * Helper class to generate list of connected halts sorted by distance.
721 */
722 struct halt_dist_node {
723 halthandle_t halt;
724 uint32 dist;
725
halt_dist_nodehalt_dist_node726 halt_dist_node(halthandle_t h = halthandle_t(), uint32 d=0) : halt(h), dist(d) {}
727
comphalt_dist_node728 static bool comp(const halt_dist_node& a, const halt_dist_node& b)
729 {
730 return a.dist < b.dist;
731 }
operator ==(const halt_dist_node & a,const halt_dist_node & b)732 friend bool operator== (const halt_dist_node& a, const halt_dist_node& b)
733 {
734 return a.halt == b.halt;
735 }
736 };
737
sort_haltlist()738 void planquadrat_t::sort_haltlist()
739 {
740 vector_tpl<halt_dist_node> halts(halt_list_count);
741 // sort with respect to distance to pos
742 const koord pos = get_kartenboden()->get_pos().get_2d();
743 for(uint8 i = 0; i<halt_list_count; i++) {
744 uint32 dist = koord_distance(halt_list[i]->get_next_pos(pos), pos);
745 halt_dist_node n(halt_list[i], dist);
746 halts.insert_unique_ordered(n, halt_dist_node::comp);
747 }
748 // put back into halt_list
749 for(uint8 i = 0; i<halt_list_count; i++) {
750 halt_list[i] = halts[i].halt;
751 }
752 }
753
754 /**
755 * removes the halt from a ground
756 * however this function check, whether there is really no other part still reachable
757 * @author prissi, neroden
758 */
remove_from_haltlist(halthandle_t halt)759 void planquadrat_t::remove_from_haltlist(halthandle_t halt)
760 {
761 halt_list_remove(halt);
762
763 // We might still be connected (to a different tile on the halt, in which case reconnect.
764
765 // quick and dirty way to our 2d koodinates ...
766 const koord pos = get_kartenboden()->get_pos().get_2d();
767 int const cov = welt->get_settings().get_station_coverage();
768 for (int y = -cov; y <= cov; y++) {
769 for (int x = -cov; x <= cov; x++) {
770 koord test_pos = pos+koord(x,y);
771 const planquadrat_t *pl = welt->access(test_pos);
772 if (pl) {
773 for( uint i = 0; i < pl->get_boden_count(); i++ ) {
774 if ( pl->get_boden_bei(i)->get_halt() == halt ) {
775 // still connected
776 // Reset distance computation
777 add_to_haltlist(halt);
778 }
779 }
780 }
781 }
782 }
783 }
784
785
786 /**
787 * true, if this halt is reachable from here
788 * @author prissi
789 */
is_connected(halthandle_t halt) const790 bool planquadrat_t::is_connected(halthandle_t halt) const
791 {
792 for( uint8 i=0; i<halt_list_count; i++ ) {
793 if(halt_list[i]==halt) {
794 return true;
795 }
796 }
797 return false;
798 }
799
update_underground() const800 void planquadrat_t::update_underground() const
801 {
802 get_kartenboden()->check_update_underground();
803 // update tunnel tiles
804 for(unsigned int i=1; i<get_boden_count(); i++) {
805 grund_t *const gr = get_boden_bei(i);
806 if (gr->ist_tunnel()) {
807 gr->check_update_underground();
808 }
809 }
810 }
811