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