1 /*
2  * Copyright (c) 1997 - 2001 Hansj�rg Malthaner
3  *
4  * This file is part of the Simutrans project under the artistic licence.
5  * (see licence.txt)
6  */
7 
8 #include <string.h>
9 #include <ctype.h>
10 
11 #ifdef MULTI_THREAD
12 #include "../utils/simthread.h"
13 static pthread_mutex_t sync_mutex = PTHREAD_MUTEX_INITIALIZER;
14 static pthread_mutex_t add_to_city_mutex = PTHREAD_MUTEX_INITIALIZER;
15 #endif
16 
17 
18 #include "../bauer/hausbauer.h"
19 #include "../gui/headquarter_info.h"
20 #include "../simworld.h"
21 #include "../simobj.h"
22 #include "../simfab.h"
23 #include "../display/simimg.h"
24 #include "../display/simgraph.h"
25 #include "../simhalt.h"
26 #include "../gui/simwin.h"
27 #include "../simcity.h"
28 #include "../player/simplay.h"
29 #include "../simdebug.h"
30 #include "../simintr.h"
31 #include "../simskin.h"
32 
33 #include "../boden/grund.h"
34 
35 
36 #include "../descriptor/building_desc.h"
37 #include "../descriptor/intro_dates.h"
38 
39 #include "../descriptor/ground_desc.h"
40 
41 #include "../utils/cbuffer_t.h"
42 #include "../utils/simrandom.h"
43 
44 #include "../dataobj/loadsave.h"
45 #include "../dataobj/translator.h"
46 #include "../dataobj/settings.h"
47 #include "../dataobj/environment.h"
48 
49 #include "../gui/obj_info.h"
50 
51 #include "gebaeude.h"
52 
53 
54 /**
55  * Initializes all variables with save, usable values
56  * @author Hj. Malthaner
57  */
init()58 void gebaeude_t::init()
59 {
60 	tile = NULL;
61 	anim_time = 0;
62 	sync = false;
63 	zeige_baugrube = false;
64 	is_factory = false;
65 	season = 0;
66 	background_animated = false;
67 	remove_ground = true;
68 	anim_frame = 0;
69 //	insta_zeit = 0; // init in set_tile()
70 	ptr.fab = NULL;
71 }
72 
73 
gebaeude_t()74 gebaeude_t::gebaeude_t() : obj_t()
75 {
76 	init();
77 }
78 
79 
gebaeude_t(loadsave_t * file)80 gebaeude_t::gebaeude_t(loadsave_t *file) : obj_t()
81 {
82 	init();
83 	rdwr(file);
84 	if(file->is_version_less(88, 2)) {
85 		set_yoff(0);
86 	}
87 	if(tile  &&  tile->get_phases()>1) {
88 		welt->sync_eyecandy.add( this );
89 		sync = true;
90 	}
91 }
92 
93 
gebaeude_t(koord3d pos,player_t * player,const building_tile_desc_t * t)94 gebaeude_t::gebaeude_t(koord3d pos, player_t *player, const building_tile_desc_t *t) :
95     obj_t(pos)
96 {
97 	set_owner( player );
98 
99 	init();
100 	if(t) {
101 		set_tile(t,true);	// this will set init time etc.
102 		player_t::add_maintenance(get_owner(), tile->get_desc()->get_maintenance(welt), tile->get_desc()->get_finance_waytype() );
103 	}
104 
105 	// get correct y offset for bridges
106 	grund_t *gr=welt->lookup(pos);
107 	if(gr  &&  gr->get_weg_hang()!=gr->get_grund_hang()) {
108 		set_yoff( -gr->get_weg_yoff() );
109 	}
110 }
111 
112 
113 /**
114  * Destructor. Removes this from the list of sync objects if necessary.
115  *
116  * @author Hj. Malthaner
117  */
~gebaeude_t()118 gebaeude_t::~gebaeude_t()
119 {
120 	if(welt->is_destroying()) {
121 		return;
122 		// avoid book-keeping
123 	}
124 
125 	if(get_stadt()) {
126 		ptr.stadt->remove_gebaeude_from_stadt(this);
127 	}
128 
129 	if(sync) {
130 		sync = false;
131 		welt->sync_eyecandy.remove(this);
132 	}
133 
134 	// tiles might be invalid, if no description is found during loading
135 	if(tile  &&  tile->get_desc()  &&  tile->get_desc()->is_attraction()) {
136 		welt->remove_attraction(this);
137 	}
138 
139 	if(tile) {
140 		player_t::add_maintenance(get_owner(), -tile->get_desc()->get_maintenance(welt), tile->get_desc()->get_finance_waytype());
141 	}
142 }
143 
144 
rotate90()145 void gebaeude_t::rotate90()
146 {
147 	obj_t::rotate90();
148 
149 	// must or can rotate?
150 	const building_desc_t* const building_desc = tile->get_desc();
151 	if (building_desc->get_all_layouts() > 1  ||  building_desc->get_x() * building_desc->get_y() > 1) {
152 		uint8 layout = tile->get_layout();
153 		koord new_offset = tile->get_offset();
154 
155 		if(building_desc->get_type() == building_desc_t::unknown  ||  building_desc->get_all_layouts()<=4) {
156 			layout = ((layout+3) % building_desc->get_all_layouts() & 3);
157 		}
158 		else if(  building_desc->get_all_layouts()==8  &&  building_desc->get_type() >= building_desc_t::city_res  ) {
159 			// eight layout city building
160 			layout = (layout & 4) + ((layout+3) & 3);
161 		}
162 		else {
163 			// 8 & 16 tile lyoutout for stations
164 			static uint8 layout_rotate[16] = { 1, 8, 5, 10, 3, 12, 7, 14, 9, 0, 13, 2, 11, 4, 15, 6 };
165 			layout = layout_rotate[layout] % building_desc->get_all_layouts();
166 		}
167 		// have to rotate the tiles :(
168 		if(  !building_desc->can_rotate()  &&  building_desc->get_all_layouts() == 1  ) {
169 			if ((welt->get_settings().get_rotation() & 1) == 0) {
170 				// rotate 180 degree
171 				new_offset = koord(building_desc->get_x() - 1 - new_offset.x, building_desc->get_y() - 1 - new_offset.y);
172 			}
173 			// do nothing here, since we cannot fix it properly
174 		}
175 		else {
176 			// rotate on ...
177 			new_offset = koord(building_desc->get_y(tile->get_layout()) - 1 - new_offset.y, new_offset.x);
178 		}
179 
180 		// such a tile exist?
181 		if(  building_desc->get_x(layout) > new_offset.x  &&  building_desc->get_y(layout) > new_offset.y  ) {
182 			const building_tile_desc_t* const new_tile = building_desc->get_tile(layout, new_offset.x, new_offset.y);
183 			// add new tile: but make them old (no construction)
184 			uint32 old_insta_zeit = insta_zeit;
185 			set_tile( new_tile, false );
186 			insta_zeit = old_insta_zeit;
187 			if(  building_desc->get_type() != building_desc_t::dock  &&  !tile->has_image()  ) {
188 				// may have a rotation, that is not recoverable
189 				if(  !is_factory  &&  new_offset!=koord(0,0)  ) {
190 					welt->set_nosave_warning();
191 				}
192 				if(  is_factory  ) {
193 					// there are factories with a broken tile
194 					// => this map rotation cannot be reloaded!
195 					welt->set_nosave();
196 				}
197 			}
198 		}
199 		else {
200 			welt->set_nosave();
201 		}
202 	}
203 }
204 
205 
206 /* sets the corresponding pointer to a factory
207  * @author prissi
208  */
set_fab(fabrik_t * fd)209 void gebaeude_t::set_fab(fabrik_t *fd)
210 {
211 	// sets the pointer in non-zero
212 	if(fd) {
213 		if(!is_factory  &&  ptr.stadt!=NULL) {
214 			dbg->fatal("gebaeude_t::set_fab()","building already bound to city!");
215 		}
216 		is_factory = true;
217 		ptr.fab = fd;
218 	}
219 	else if(is_factory) {
220 		ptr.fab = NULL;
221 	}
222 }
223 
224 
225 /* sets the corresponding city
226  * @author prissi
227  */
set_stadt(stadt_t * s)228 void gebaeude_t::set_stadt(stadt_t *s)
229 {
230 	if(is_factory  &&  ptr.fab!=NULL) {
231 		dbg->fatal("gebaeude_t::set_stadt()","building at (%s) already bound to factory!", get_pos().get_str() );
232 	}
233 	// sets the pointer in non-zero
234 	is_factory = false;
235 	ptr.stadt = s;
236 }
237 
238 
239 /* make this building without construction */
add_alter(uint32 a)240 void gebaeude_t::add_alter(uint32 a)
241 {
242 	insta_zeit -= min(a,insta_zeit);
243 }
244 
245 
set_tile(const building_tile_desc_t * new_tile,bool start_with_construction)246 void gebaeude_t::set_tile( const building_tile_desc_t *new_tile, bool start_with_construction )
247 {
248 	insta_zeit = welt->get_ticks();
249 
250 	if(!zeige_baugrube  &&  tile!=NULL) {
251 		// mark old tile dirty
252 		mark_images_dirty();
253 	}
254 
255 	zeige_baugrube = !new_tile->get_desc()->no_construction_pit()  &&  start_with_construction;
256 	if(sync) {
257 		if(  new_tile->get_phases()<=1  &&  !zeige_baugrube  ) {
258 			// need to stop animation
259 #ifdef MULTI_THREAD
260 			pthread_mutex_lock( &sync_mutex );
261 #endif
262 			welt->sync_eyecandy.remove(this);
263 			sync = false;
264 			anim_frame = 0;
265 #ifdef MULTI_THREAD
266 			pthread_mutex_unlock( &sync_mutex );
267 #endif
268 		}
269 	}
270 	else if(  (new_tile->get_phases()>1  &&  (!is_factory  ||  get_fabrik()->is_currently_producing()) ) ||  zeige_baugrube  ) {
271 		// needs now animation
272 #ifdef MULTI_THREAD
273 		pthread_mutex_lock( &sync_mutex );
274 #endif
275 		anim_frame = sim_async_rand( new_tile->get_phases() );
276 		anim_time = 0;
277 		welt->sync_eyecandy.add(this);
278 		sync = true;
279 #ifdef MULTI_THREAD
280 		pthread_mutex_unlock( &sync_mutex );
281 #endif
282 	}
283 	tile = new_tile;
284 	remove_ground = tile->has_image()  &&  !tile->get_desc()->needs_ground();
285 	set_flag(obj_t::dirty);
286 }
287 
288 
sync_step(uint32 delta_t)289 sync_result gebaeude_t::sync_step(uint32 delta_t)
290 {
291 	if(  zeige_baugrube  ) {
292 		// still under construction?
293 		if(  welt->get_ticks() - insta_zeit > 5000  ) {
294 			set_flag( obj_t::dirty );
295 			mark_image_dirty( get_image(), 0 );
296 			zeige_baugrube = false;
297 			if(  tile->get_phases() <= 1  ) {
298 				sync = false;
299 				return SYNC_REMOVE;
300 			}
301 		}
302 	}
303 	else {
304 		if(  !is_factory  ||  get_fabrik()->is_currently_producing()  ) {
305 			// normal animated building
306 			anim_time += delta_t;
307 			if(  anim_time > tile->get_desc()->get_animation_time()  ) {
308 				anim_time -= tile->get_desc()->get_animation_time();
309 
310 				// old positions need redraw
311 				if(  background_animated  ) {
312 					set_flag( obj_t::dirty );
313 					mark_images_dirty();
314 				}
315 				else {
316 					// try foreground
317 					image_id image = tile->get_foreground( anim_frame, season );
318 					mark_image_dirty( image, 0 );
319 				}
320 
321 				anim_frame++;
322 				if(  anim_frame >= tile->get_phases()  ) {
323 					anim_frame = 0;
324 				}
325 
326 				if(  !background_animated  ) {
327 					// next phase must be marked dirty too ...
328 					image_id image = tile->get_foreground( anim_frame, season );
329 					mark_image_dirty( image, 0 );
330 				}
331  			}
332 		}
333 	}
334 	return SYNC_OK;
335 }
336 
337 
calc_image()338 void gebaeude_t::calc_image()
339 {
340 	grund_t *gr = welt->lookup( get_pos() );
341 	// need no ground?
342 	if(  remove_ground  &&  gr->get_typ() == grund_t::fundament  ) {
343 		gr->set_image( IMG_EMPTY );
344 	}
345 
346 	static uint8 effective_season[][5] = { {0,0,0,0,0}, {0,0,0,0,1}, {0,0,0,0,1}, {0,1,2,3,2}, {0,1,2,3,4} };  // season image lookup from [number of images] and [actual season/snow]
347 
348 	if(  (gr->ist_tunnel()  &&  !gr->ist_karten_boden())  ||  tile->get_seasons() < 2  ) {
349 		season = 0;
350 	}
351 	else if(  get_pos().z - (get_yoff() / TILE_HEIGHT_STEP) >= welt->get_snowline()  ||  welt->get_climate( get_pos().get_2d() ) == arctic_climate  ) {
352 		// snowy winter graphics
353 		season = effective_season[tile->get_seasons() - 1][4];
354 	}
355 	else if(  get_pos().z - (get_yoff() / TILE_HEIGHT_STEP) >= welt->get_snowline() - 1  &&  welt->get_season() == 0  ) {
356 		// snowline crossing in summer
357 		// so at least some weeks spring/autumn
358 		season = effective_season[tile->get_seasons() - 1][welt->get_last_month() <= 5 ? 3 : 1];
359 	}
360 	else {
361 		season = effective_season[tile->get_seasons() - 1][welt->get_season()];
362 	}
363 
364 	background_animated = tile->is_background_animated( season );
365 }
366 
367 
get_image() const368 image_id gebaeude_t::get_image() const
369 {
370 	if(env_t::hide_buildings!=0  &&  tile->has_image()) {
371 		// opaque houses
372 		if(is_city_building()) {
373 			return env_t::hide_with_transparency ? skinverwaltung_t::fussweg->get_image_id(0) : skinverwaltung_t::construction_site->get_image_id(0);
374 		}
375 		else if(  (env_t::hide_buildings == env_t::ALL_HIDDEN_BUILDING  &&  tile->get_desc()->get_type() < building_desc_t::others)) {
376 			// hide with transparency or tile without information
377 			if(env_t::hide_with_transparency) {
378 				if(tile->get_desc()->get_type() == building_desc_t::factory  &&  ptr.fab->get_desc()->get_placement() == factory_desc_t::Water) {
379 					// no ground tiles for water things
380 					return IMG_EMPTY;
381 				}
382 				return skinverwaltung_t::fussweg->get_image_id(0);
383 			}
384 			else {
385 				uint16 kind=skinverwaltung_t::construction_site->get_count()<=tile->get_desc()->get_type() ? skinverwaltung_t::construction_site->get_count()-1 : tile->get_desc()->get_type();
386 				return skinverwaltung_t::construction_site->get_image_id( kind );
387 			}
388 		}
389 	}
390 
391 	if(  zeige_baugrube  )  {
392 		return skinverwaltung_t::construction_site->get_image_id(0);
393 	}
394 	else {
395 		return tile->get_background( anim_frame, 0, season );
396 	}
397 }
398 
399 
get_outline_image() const400 image_id gebaeude_t::get_outline_image() const
401 {
402 	if(env_t::hide_buildings!=0  &&  env_t::hide_with_transparency  &&  !zeige_baugrube) {
403 		// opaque houses
404 		return tile->get_background( anim_frame, 0, season );
405 	}
406 	return IMG_EMPTY;
407 }
408 
409 
410 /* gives outline colour and plots background tile if needed for transparent view */
get_outline_colour() const411 FLAGGED_PIXVAL gebaeude_t::get_outline_colour() const
412 {
413 	uint8 colours[] = { COL_BLACK, COL_YELLOW, COL_YELLOW, COL_PURPLE, COL_RED, COL_GREEN };
414 	FLAGGED_PIXVAL disp_colour = 0;
415 	if(env_t::hide_buildings!=env_t::NOT_HIDE) {
416 		if(is_city_building()) {
417 			disp_colour = color_idx_to_rgb(colours[0]) | TRANSPARENT50_FLAG | OUTLINE_FLAG;
418 		}
419 		else if (env_t::hide_buildings == env_t::ALL_HIDDEN_BUILDING && tile->get_desc()->get_type() < building_desc_t::others) {
420 			// special building
421 			disp_colour = color_idx_to_rgb(colours[tile->get_desc()->get_type()]) | TRANSPARENT50_FLAG | OUTLINE_FLAG;
422 		}
423 	}
424 	return disp_colour;
425 }
426 
427 
get_image(int nr) const428 image_id gebaeude_t::get_image(int nr) const
429 {
430 	if(zeige_baugrube || env_t::hide_buildings) {
431 		return IMG_EMPTY;
432 	}
433 	else {
434 		return tile->get_background( anim_frame, nr, season );
435 	}
436 }
437 
438 
get_front_image() const439 image_id gebaeude_t::get_front_image() const
440 {
441 	if(zeige_baugrube) {
442 		return IMG_EMPTY;
443 	}
444 	if (env_t::hide_buildings != 0   &&  (is_city_building()  ||  (env_t::hide_buildings == env_t::ALL_HIDDEN_BUILDING  &&  tile->get_desc()->get_type() < building_desc_t::others))) {
445 		return IMG_EMPTY;
446 	}
447 	else {
448 		// Show depots, station buildings etc.
449 		return tile->get_foreground( anim_frame, season );
450 	}
451 }
452 
453 
454 /**
455  * calculate the passenger level as function of the city size (if there)
456  */
get_passagier_level() const457 int gebaeude_t::get_passagier_level() const
458 {
459 	koord dim = tile->get_desc()->get_size();
460 	sint32 pax = tile->get_desc()->get_level();
461 	if(  !is_factory  &&  ptr.stadt != NULL  ) {
462 		// belongs to a city ...
463 		return ((pax + 6) >> 2) * welt->get_settings().get_passenger_factor() / 16;
464 	}
465 	return pax*dim.x*dim.y;
466 }
467 
468 
get_mail_level() const469 int gebaeude_t::get_mail_level() const
470 {
471 	koord dim = tile->get_desc()->get_size();
472 	sint32 mail = tile->get_desc()->get_mail_level();
473 	if(  !is_factory  &&  ptr.stadt != NULL  ) {
474 		return ((mail + 5) >> 2) * welt->get_settings().get_passenger_factor() / 16;
475 	}
476 	return mail*dim.x*dim.y;
477 }
478 
479 
480 /**
481  * @return eigener Name oder Name der Fabrik falls Teil einer Fabrik
482  * @author Hj. Malthaner
483  */
get_name() const484 const char *gebaeude_t::get_name() const
485 {
486 	if(is_factory  &&  ptr.fab) {
487 		return ptr.fab->get_name();
488 	}
489 	switch(tile->get_desc()->get_type()) {
490 				case building_desc_t::attraction_city:   return "Besonderes Gebaeude";
491 				case building_desc_t::attraction_land:   return "Sehenswuerdigkeit";
492 				case building_desc_t::monument:           return "Denkmal";
493 				case building_desc_t::townhall:           return "Rathaus";
494 				default: break;
495 	}
496 	return "Gebaeude";
497 }
498 
499 
500 /**
501  * waytype associated with this object
502  */
get_waytype() const503 waytype_t gebaeude_t::get_waytype() const
504 {
505 	const building_desc_t *desc = tile->get_desc();
506 	waytype_t wt = invalid_wt;
507 
508 	const building_desc_t::btype type = tile->get_desc()->get_type();
509 	if (type == building_desc_t::depot  ||  type == building_desc_t::generic_stop  ||  type == building_desc_t::generic_extension) {
510 		wt = (waytype_t)desc->get_extra();
511 	}
512 	return wt;
513 }
514 
515 
is_townhall() const516 bool gebaeude_t::is_townhall() const
517 {
518 	return tile->get_desc()->is_townhall();
519 }
520 
521 
is_monument() const522 bool gebaeude_t::is_monument() const
523 {
524 	return tile->get_desc()->get_type() == building_desc_t::monument;
525 }
526 
527 
is_headquarter() const528 bool gebaeude_t::is_headquarter() const
529 {
530 	return tile->get_desc()->is_headquarters();
531 }
532 
533 
is_city_building() const534 bool gebaeude_t::is_city_building() const
535 {
536 	return tile->get_desc()->is_city_building();
537 }
538 
539 
show_info()540 void gebaeude_t::show_info()
541 {
542 	if(get_fabrik()) {
543 		ptr.fab->open_info_window();
544 		return;
545 	}
546 	int old_count = win_get_open_count();
547 	bool special = is_headquarter() || is_townhall();
548 
549 	if(is_headquarter()) {
550 		create_win( new headquarter_info_t(get_owner()), w_info, magic_headquarter+get_owner()->get_player_nr() );
551 	}
552 	else if (is_townhall()) {
553 		ptr.stadt->open_info_window();
554 	}
555 
556 	if(!tile->get_desc()->no_info_window()) {
557 		if(!special  ||  (env_t::townhall_info  &&  old_count==win_get_open_count()) ) {
558 			// iterate over all places to check if there is already an open window
559 			const building_desc_t* const building_desc = tile->get_desc();
560 			const uint8 layout = tile->get_layout();
561 			koord k;
562 			for (k.x = 0; k.x<building_desc->get_x(layout); k.x++) {
563 				for (k.y = 0; k.y<building_desc->get_y(layout); k.y++) {
564 					const building_tile_desc_t *tile = building_desc->get_tile(layout, k.x, k.y);
565 					if (tile == NULL || !tile->has_image()) {
566 						continue;
567 					}
568 					if (grund_t *gr = welt->lookup(get_pos() - get_tile()->get_offset() + k)) {
569 						gebaeude_t *gb = gr->find<gebaeude_t>();
570 						if (gb  &&  gb->get_tile() == tile) {
571 							if (win_get_magic((ptrdiff_t)gb)) {
572 								// already open
573 								return;
574 							}
575 						}
576 					}
577 				}
578 			}
579 			// open info window for the first tile of our building (not relying on presence of (0,0) tile)
580 			get_first_tile()->obj_t::show_info();
581 		}
582 	}
583 }
584 
585 
is_same_building(const gebaeude_t * other) const586 bool gebaeude_t::is_same_building(const gebaeude_t* other) const
587 {
588 	if (other) {
589 		const building_tile_desc_t* otile = other->get_tile();
590 		// same descriptor and house tile
591 		if (get_tile()->get_desc() == otile->get_desc()  &&  get_tile()->get_layout() == otile->get_layout()
592 			// same position of (0,0) tile
593 			&&  (get_pos() - get_tile()->get_offset()  == other->get_pos() - otile->get_offset())) {
594 			return true;
595 		}
596 	}
597 	return false;
598 }
599 
600 
get_first_tile()601 gebaeude_t* gebaeude_t::get_first_tile()
602 {
603 	const building_desc_t* const building_desc = tile->get_desc();
604 	const uint8 layout = tile->get_layout();
605 	koord k;
606 	for(k.x=0; k.x<building_desc->get_x(layout); k.x++) {
607 		for(k.y=0; k.y<building_desc->get_y(layout); k.y++) {
608 			const building_tile_desc_t *tile = building_desc->get_tile(layout, k.x, k.y);
609 			if (tile==NULL  ||  !tile->has_image()) {
610 				continue;
611 			}
612 			if (grund_t *gr = welt->lookup( get_pos() - get_tile()->get_offset() + k)) {
613 				gebaeude_t *gb = gr->find<gebaeude_t>();
614 				if (gb  &&  gb->get_tile() == tile) {
615 					return gb;
616 				}
617 			}
618 		}
619 	}
620 	return this;
621 }
622 
623 
info(cbuffer_t & buf) const624 void gebaeude_t::info(cbuffer_t & buf) const
625 {
626 	obj_t::info(buf);
627 
628 	if(is_factory  &&  ptr.fab != NULL) {
629 		buf.append((char *)0);
630 	}
631 	else if(zeige_baugrube) {
632 		buf.append(translator::translate("Baustelle"));
633 		buf.append("\n");
634 	}
635 	else {
636 		const char *desc = tile->get_desc()->get_name();
637 		if(desc != NULL) {
638 			const char *trans_desc = translator::translate(desc);
639 			if(trans_desc==desc) {
640 				// no description here
641 				switch(tile->get_desc()->get_type()) {
642 					case building_desc_t::city_res:
643 						trans_desc = translator::translate("residential house");
644 						break;
645 					case building_desc_t::city_ind:
646 						trans_desc = translator::translate("industrial building");
647 						break;
648 					case building_desc_t::city_com:
649 						trans_desc = translator::translate("shops and stores");
650 						break;
651 					default:
652 						// use file name
653 						break;
654 				}
655 				buf.append(trans_desc);
656 			}
657 			else {
658 				// since the format changed, we remove all but double newlines
659 				char *text = new char[strlen(trans_desc)+1];
660 				char *dest = text;
661 				const char *src = trans_desc;
662 				while(  *src!=0  ) {
663 					*dest = *src;
664 					if(src[0]=='\n') {
665 						if(src[1]=='\n') {
666 							src ++;
667 							dest++;
668 							*dest = '\n';
669 						}
670 						else {
671 							*dest = ' ';
672 						}
673 					}
674 					src ++;
675 					dest ++;
676 				}
677 				// remove double line breaks at the end
678 				*dest = 0;
679 				while( dest>text  &&  *--dest=='\n'  ) {
680 					*dest = 0;
681 				}
682 
683 				buf.append(text);
684 				delete [] text;
685 			}
686 		}
687 		buf.append( "\n\n" );
688 
689 		// belongs to which city?
690 		if(  !is_factory  &&  ptr.stadt != NULL  ) {
691 			buf.printf(translator::translate("Town: %s\n"), ptr.stadt->get_name());
692 		}
693 
694 		if(  !get_tile()->get_desc()->is_transport_building()  ) {
695 			buf.printf("%s: %d\n", translator::translate("Passagierrate"), get_passagier_level());
696 			buf.printf("%s: %d\n", translator::translate("Postrate"),      get_mail_level());
697 		}
698 
699 		building_desc_t const& h = *tile->get_desc();
700 		buf.printf("%s%u", translator::translate("\nBauzeit von"), h.get_intro_year_month() / 12);
701 		if (h.get_retire_year_month() != DEFAULT_RETIRE_DATE * 12) {
702 			buf.printf("%s%u", translator::translate("\nBauzeit bis"), h.get_retire_year_month() / 12);
703 		}
704 
705 		buf.append("\n");
706 		if(get_owner()==NULL) {
707 			const sint32 v = (sint32)( -welt->get_settings().cst_multiply_remove_haus * (tile->get_desc()->get_level() + 1) / 100 );
708 			buf.printf("\n%s: %ld$\n", translator::translate("Wert"), v);
709 		}
710 
711 		if (char const* const maker = tile->get_desc()->get_copyright()) {
712 			buf.append("\n");
713 			buf.printf(translator::translate("Constructed by %s"), maker);
714 		}
715 #ifdef DEBUG
716 		buf.append( "\n\nrotation " );
717 		buf.append( tile->get_layout(), 0 );
718 		buf.append( " best layout " );
719 		buf.append( stadt_t::orient_city_building( get_pos().get_2d() - tile->get_offset(), tile->get_desc(), koord(3,3) ), 0 );
720 		buf.append( "\n" );
721 #endif
722 	}
723 }
724 
725 
rdwr(loadsave_t * file)726 void gebaeude_t::rdwr(loadsave_t *file)
727 {
728 	// do not save factory buildings => factory will reconstruct them
729 	assert(!is_factory);
730 	xml_tag_t d( file, "gebaeude_t" );
731 
732 	obj_t::rdwr(file);
733 
734 	char buf[128];
735 	short idx;
736 
737 	if(file->is_saving()) {
738 		const char *s = tile->get_desc()->get_name();
739 		file->rdwr_str(s);
740 		idx = tile->get_index();
741 	}
742 	else {
743 		file->rdwr_str(buf, lengthof(buf));
744 	}
745 	file->rdwr_short(idx);
746 	file->rdwr_long(insta_zeit);
747 
748 	if(file->is_loading()) {
749 		tile = hausbauer_t::find_tile(buf, idx);
750 		if(tile==NULL) {
751 			// try with compatibility list first
752 			tile = hausbauer_t::find_tile(translator::compatibility_name(buf), idx);
753 			if(tile==NULL) {
754 				DBG_MESSAGE("gebaeude_t::rdwr()","neither %s nor %s, tile %i not found, try other replacement",translator::compatibility_name(buf),buf,idx);
755 			}
756 			else {
757 				DBG_MESSAGE("gebaeude_t::rdwr()","%s replaced by %s, tile %i",buf,translator::compatibility_name(buf),idx);
758 			}
759 		}
760 		if(tile==NULL) {
761 			// first check for special buildings
762 			if(strstr(buf,"TrainStop")!=NULL) {
763 				tile = hausbauer_t::find_tile("TrainStop", idx);
764 			} else if(strstr(buf,"BusStop")!=NULL) {
765 				tile = hausbauer_t::find_tile("BusStop", idx);
766 			} else if(strstr(buf,"ShipStop")!=NULL) {
767 				tile = hausbauer_t::find_tile("ShipStop", idx);
768 			} else if(strstr(buf,"PostOffice")!=NULL) {
769 				tile = hausbauer_t::find_tile("PostOffice", idx);
770 			} else if(strstr(buf,"StationBlg")!=NULL) {
771 				tile = hausbauer_t::find_tile("StationBlg", idx);
772 			}
773 			else {
774 				// try to find a fitting building
775 				int level=atoi(buf);
776 				building_desc_t::btype type = building_desc_t::unknown;
777 
778 				if(level>0) {
779 					// May be an old 64er, so we can try some
780 					if(strncmp(buf+3,"WOHN",4)==0) {
781 						type = building_desc_t::city_res;
782 					} else if(strncmp(buf+3,"FAB",3)==0) {
783 						type = building_desc_t::city_ind;
784 					}
785 					else {
786 						type = building_desc_t::city_com;
787 					}
788 					level --;
789 				}
790 				else if(buf[3]=='_') {
791 					/* should have the form of RES/IND/COM_xx_level
792 					 * xx is usually a number by can be anything without underscores
793 					 */
794 					level = atoi(strrchr( buf, '_' )+1);
795 					if(level>0) {
796 						switch(toupper(buf[0])) {
797 							case 'R': type = building_desc_t::city_res; break;
798 							case 'I': type = building_desc_t::city_ind; break;
799 							case 'C': type = building_desc_t::city_com; break;
800 						}
801 					}
802 					level --;
803 				}
804 				// we try to replace citybuildings with their matching counterparts
805 				// if none are matching, we try again without climates and timeline!
806 				switch(type) {
807 					case building_desc_t::city_res:
808 						{
809 							const building_desc_t *bdsc = hausbauer_t::get_residential( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ), 0, koord(1,1), koord(1,1) );
810 							if(bdsc==NULL) {
811 								bdsc = hausbauer_t::get_residential(level,0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) );
812 							}
813 							if( bdsc) {
814 								dbg->message("gebaeude_t::rwdr", "replace unknown building %s with residence level %i by %s",buf,level,bdsc->get_name());
815 								tile = bdsc->get_tile(0);
816 							}
817 						}
818 						break;
819 
820 					case building_desc_t::city_com:
821 						{
822 							// for replacement, ignore cluster and size
823 							const building_desc_t *bdsc = hausbauer_t::get_commercial( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ), 0, koord(1,1), koord(1,1) );
824 							if(bdsc==NULL) {
825 								bdsc = hausbauer_t::get_commercial(level, 0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) );
826 							}
827 							if(bdsc) {
828 								dbg->message("gebaeude_t::rwdr", "replace unknown building %s with commercial level %i by %s",buf,level,bdsc->get_name());
829 								tile = bdsc->get_tile(0);
830 							}
831 						}
832 						break;
833 
834 					case building_desc_t::city_ind:
835 						{
836 							const building_desc_t *bdsc = hausbauer_t::get_industrial( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ), 0, koord(1,1), koord(1,1) );
837 							if(bdsc==NULL) {
838 								bdsc = hausbauer_t::get_industrial(level, 0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) );
839 								if(bdsc==NULL) {
840 									bdsc = hausbauer_t::get_residential(level, 0, MAX_CLIMATES, 0, koord(1,1), koord(1,1) );
841 								}
842 							}
843 							if (bdsc) {
844 								dbg->message("gebaeude_t::rwdr", "replace unknown building %s with industry level %i by %s",buf,level,bdsc->get_name());
845 								tile = bdsc->get_tile(0);
846 							}
847 						}
848 						break;
849 
850 					default:
851 						dbg->warning("gebaeude_t::rwdr", "description %s for building at %d,%d not found (will be removed)!", buf, get_pos().x, get_pos().y);
852 						welt->add_missing_paks( buf, karte_t::MISSING_BUILDING );
853 				}
854 			}
855 		}	// here we should have a valid tile pointer or nothing ...
856 
857 		/* avoid double construction of monuments:
858 		 * remove them from selection lists
859 		 */
860 		if (tile  &&  tile->get_desc()->get_type() == building_desc_t::monument) {
861 			hausbauer_t::monument_erected(tile->get_desc());
862 		}
863 		if (tile) {
864 			remove_ground = tile->has_image()  &&  !tile->get_desc()->needs_ground();
865 		}
866 	}
867 
868 	if(file->is_version_less(99, 6)) {
869 		// ignore the sync flag
870 		uint8 dummy=sync;
871 		file->rdwr_byte(dummy);
872 	}
873 
874 	// restore city pointer here
875 	if(  file->is_version_atleast(99, 14)  ) {
876 		sint32 city_index = -1;
877 		if(  file->is_saving()  &&  ptr.stadt!=NULL  ) {
878 			city_index = welt->get_cities().index_of( ptr.stadt );
879 		}
880 		file->rdwr_long(city_index);
881 		if(  file->is_loading()  &&  city_index!=-1  &&  (tile==NULL  ||  tile->get_desc()==NULL  ||  tile->get_desc()->is_connected_with_town())  ) {
882 			ptr.stadt = welt->get_cities()[city_index];
883 		}
884 	}
885 
886 	if(file->is_loading()) {
887 		anim_frame = 0;
888 		anim_time = 0;
889 		sync = false;
890 
891 		// Hajo: rebuild tourist attraction list
892 		if(tile && tile->get_desc()->is_attraction()) {
893 			welt->add_attraction( this );
894 		}
895 	}
896 }
897 
898 
899 /**
900  * Wird nach dem Laden der Welt aufgerufen - �blicherweise benutzt
901  * um das Aussehen des Dings an Boden und Umgebung anzupassen
902  *
903  * @author Hj. Malthaner
904  */
finish_rd()905 void gebaeude_t::finish_rd()
906 {
907 	player_t::add_maintenance(get_owner(), tile->get_desc()->get_maintenance(welt), tile->get_desc()->get_finance_waytype());
908 
909 	// citybuilding, but no town?
910 	if(  tile->get_offset()==koord(0,0)  ) {
911 		if(  tile->get_desc()->is_connected_with_town()  ) {
912 			stadt_t *city = (ptr.stadt==NULL) ? welt->find_nearest_city( get_pos().get_2d() ) : ptr.stadt;
913 			if(city) {
914 #ifdef MULTI_THREAD
915 				pthread_mutex_lock( &add_to_city_mutex );
916 #endif
917 				city->add_gebaeude_to_stadt(this, true);
918 #ifdef MULTI_THREAD
919 				pthread_mutex_unlock( &add_to_city_mutex );
920 #endif
921 			}
922 		}
923 		else if(  !is_factory  ) {
924 			ptr.stadt = NULL;
925 		}
926 	}
927 }
928 
929 
cleanup(player_t * player)930 void gebaeude_t::cleanup(player_t *player)
931 {
932 //	DBG_MESSAGE("gebaeude_t::entferne()","gb %i");
933 	// remove costs
934 	sint64 cost = welt->get_settings().cst_multiply_remove_haus;
935 
936 	// tearing down halts is always single costs only
937 	if (!tile->get_desc()->is_transport_building()) {
938 		cost *= tile->get_desc()->get_level() + 1;
939 	}
940 
941 	player_t::book_construction_costs(player, cost, get_pos().get_2d(), tile->get_desc()->get_finance_waytype());
942 
943 	// may need to update next buildings, in the case of start, middle, end buildings
944 	if(tile->get_desc()->get_all_layouts()>1  &&  !is_city_building()) {
945 
946 		// realign surrounding buildings...
947 		uint32 layout = tile->get_layout();
948 
949 		// detect if we are connected at far (north/west) end
950 		grund_t * gr = welt->lookup( get_pos() );
951 		if(gr) {
952 			sint8 offset = gr->get_weg_yoff()/TILE_HEIGHT_STEP;
953 			gr = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::east : koord::south), offset) );
954 			if(!gr) {
955 				// check whether bridge end tile
956 				grund_t * gr_tmp = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::east : koord::south),offset - 1) );
957 				if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) {
958 					gr = gr_tmp;
959 				}
960 			}
961 			if(gr) {
962 				gebaeude_t* gb = gr->find<gebaeude_t>();
963 				if(gb  &&  gb->get_tile()->get_desc()->get_all_layouts()>4u) {
964 					koord xy = gb->get_tile()->get_offset();
965 					uint8 layoutbase = gb->get_tile()->get_layout();
966 					if((layoutbase & 1u) == (layout & 1u)) {
967 						layoutbase |= 4u; // set far bit on neighbour
968 						gb->set_tile( gb->get_tile()->get_desc()->get_tile(layoutbase, xy.x, xy.y), false );
969 					}
970 				}
971 			}
972 
973 			// detect if near (south/east) end
974 			gr = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::west : koord::north), offset) );
975 			if(!gr) {
976 				// check whether bridge end tile
977 				grund_t * gr_tmp = welt->lookup( get_pos()+koord3d( (layout & 1 ? koord::west : koord::north),offset - 1) );
978 				if(gr_tmp && gr_tmp->get_weg_yoff()/TILE_HEIGHT_STEP == 1) {
979 					gr = gr_tmp;
980 				}
981 			}
982 			if(gr) {
983 				gebaeude_t* gb = gr->find<gebaeude_t>();
984 				if(gb  &&  gb->get_tile()->get_desc()->get_all_layouts()>4) {
985 					koord xy = gb->get_tile()->get_offset();
986 					uint8 layoutbase = gb->get_tile()->get_layout();
987 					if((layoutbase & 1u) == (layout & 1u)) {
988 						layoutbase |= 2u; // set near bit on neighbour
989 						gb->set_tile( gb->get_tile()->get_desc()->get_tile(layoutbase, xy.x, xy.y), false );
990 					}
991 				}
992 			}
993 		}
994 	}
995 	mark_images_dirty();
996 }
997 
998 
mark_images_dirty() const999 void gebaeude_t::mark_images_dirty() const
1000 {
1001 	// remove all traces from the screen
1002 	image_id img;
1003 	if(  zeige_baugrube  ||
1004 			(!env_t::hide_with_transparency  &&
1005 				env_t::hide_buildings>(is_city_building() ? env_t::NOT_HIDE : env_t::SOME_HIDDEN_BUILDING))  ) {
1006 		img = skinverwaltung_t::construction_site->get_image_id(0);
1007 	}
1008 	else {
1009 		img = tile->get_background( anim_frame, 0, season ) ;
1010 	}
1011 	for(  int i=0;  img!=IMG_EMPTY;  img=get_image(++i)  ) {
1012 		mark_image_dirty( img, -(i*get_tile_raster_width()) );
1013 	}
1014 }
1015