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