diff --git a/bauer/hausbauer.cc b/bauer/hausbauer.cc index 34ec6668c..c6ede5e40 100644 --- a/bauer/hausbauer.cc +++ b/bauer/hausbauer.cc @@ -298,7 +298,7 @@ void hausbauer_t::new_world() } -void hausbauer_t::remove( player_t *player, gebaeude_t *gb ) +void hausbauer_t::remove( player_t *player, const gebaeude_t *gb ) { const building_tile_desc_t *tile = gb->get_tile(); const building_desc_t *bdsc = tile->get_desc(); @@ -807,6 +807,15 @@ const building_desc_t* hausbauer_t::get_special(uint32 bev, building_desc_t::bty return pick_any_weighted(auswahl); } +bool is_allowed_size(const building_desc_t* bldg, koord size) { + if(size.x==-1 || bldg->get_size()==size) { + return true; + } else if(bldg->get_size().x==size.y && bldg->get_size().y==size.x) { + return true; + } else { + return false; + } +} /** * Tries to find a matching house desc from @p list. @@ -814,14 +823,14 @@ const building_desc_t* hausbauer_t::get_special(uint32 bev, building_desc_t::bty * @param level the minimum level of the house/station * @param cl allowed climates */ -static const building_desc_t* get_city_building_from_list(const vector_tpl& list, int level, uint16 time, climate cl, uint32 clusters ) +const building_desc_t* hausbauer_t::get_city_building_from_list(const vector_tpl& list, int level, koord size, uint16 time, climate cl, uint32 clusters ) { weighted_vector_tpl selections(16); // DBG_MESSAGE("hausbauer_t::get_aus_liste()","target level %i", level ); const building_desc_t *desc_at_least=NULL; FOR(vector_tpl, const desc, list) { - if( desc->is_allowed_climate(cl) && desc->get_distribution_weight()>0 && desc->is_available(time) ) { + if( desc->is_allowed_climate(cl) && desc->get_distribution_weight()>0 && desc->is_available(time) && is_allowed_size(desc, size) ) { desc_at_least = desc; } @@ -837,7 +846,7 @@ static const building_desc_t* get_city_building_from_list(const vector_tplget_distribution_weight() > 0 ) { + if( thislevel == level && is_allowed_size(desc,size) && desc->get_distribution_weight() > 0 ) { if( cl==MAX_CLIMATES || desc->is_allowed_climate(cl) ) { if( desc->is_available(time) ) { // DBG_MESSAGE("hausbauer_t::get_city_building_from_list()","appended %s at %i", desc->get_name(), thislevel ); @@ -872,22 +881,132 @@ static const building_desc_t* get_city_building_from_list(const vector_tpl& list, koord pos_origin, koord size, uint16 time, climate cl, uint32 clusters ) { - return get_city_building_from_list(city_commercial, level, time, cl, clusters); + weighted_vector_tpl selections(16); + // calculate sum of level of replaced buildings. + uint16 sum_level = 0; + bool checked[64][64]; + // initialize check flag. + for(uint8 i=0; ilookup_kartenboden(pos_origin+koord(x,y)); + if( !gr || gr->ist_natur() ) { + continue; + } + const gebaeude_t* gb = obj_cast(gr->first_obj());; + if(!(gb && gb->is_city_building())) { + continue; + } + sum_level += gb->get_tile()->get_desc()->get_level(); + const uint8 gb_layout = gb->get_tile()->get_layout(); + const koord gb_size = gb->get_tile()->get_desc()->get_size(gb_layout); + for(uint8 gx=0; gxget_settings().get_max_level_leap_per_a_tile(); + + // try to find a suitable building. + FOR(vector_tpl, const desc, list) { + // only allow buildings of the designated size. + if(!is_allowed_size(desc, size)) { + continue; + } + + const int thislevel = desc->get_level(); + if(thislevel>sum_level) { + if (selections.empty() && thislevel-level_replaced<=level_leap_limit*area_of_building) { + // Nothing of the correct level. Continue with search on a higher level. + sum_level = thislevel; + } + else { + // We already found something of the correct level; stop. + break; + } + } + + if( thislevel == sum_level && desc->get_distribution_weight() > 0 ) { + if( cl==MAX_CLIMATES || desc->is_allowed_climate(cl) ) { + if( desc->is_available(time) ) { + /* Level, time period, and climate are all OK. + * Now modify the chance rating by a factor based on the clusters. + */ + // FIXME: the factor should be configurable by the pakset/ + int chance = desc->get_distribution_weight(); + if( clusters ) { + uint32 my_clusters = desc->get_clusters(); + if( my_clusters & clusters ) { + chance *= stadt_t::get_cluster_factor(); + } + else { + chance /= stadt_t::get_cluster_factor(); + } + } + selections.append(desc, chance); + } + } + } + } + + if(selections.get_sum_weight()==0) { + return NULL; + } + if(selections.get_count()==1) { + return selections.front(); + } + // now there is something to choose + return pick_any_weighted(selections); } -const building_desc_t* hausbauer_t::get_industrial(int level, uint16 time, climate cl, uint32 clusters) +const building_desc_t* hausbauer_t::get_commercial(int level, koord size, uint16 time, climate cl, uint32 clusters) { - return get_city_building_from_list(city_industry, level, time, cl, clusters); + return get_city_building_from_list(city_commercial, level, size, time, cl, clusters); } +const building_desc_t* hausbauer_t::get_commercial(koord pos, koord size, uint16 time, climate cl, uint32 clusters) +{ + return get_city_building_from_list(city_commercial, pos, size, time, cl, clusters); +} + +const building_desc_t* hausbauer_t::get_industrial(int level, koord size, uint16 time, climate cl, uint32 clusters) +{ + return get_city_building_from_list(city_industry, level, size, time, cl, clusters); +} +const building_desc_t* hausbauer_t::get_industrial(koord pos, koord size, uint16 time, climate cl, uint32 clusters) +{ + return get_city_building_from_list(city_industry, pos, size, time, cl, clusters); +} -const building_desc_t* hausbauer_t::get_residential(int level, uint16 time, climate cl, uint32 clusters) +const building_desc_t* hausbauer_t::get_residential(int level, koord size, uint16 time, climate cl, uint32 clusters) +{ + return get_city_building_from_list(city_residential, level, size, time, cl, clusters); +} +const building_desc_t* hausbauer_t::get_residential(koord pos, koord size, uint16 time, climate cl, uint32 clusters) { - return get_city_building_from_list(city_residential, level, time, cl, clusters); + return get_city_building_from_list(city_residential, pos, size, time, cl, clusters); } diff --git a/bauer/hausbauer.h b/bauer/hausbauer.h index 749d3d23b..96a50ffe2 100644 --- a/bauer/hausbauer.h +++ b/bauer/hausbauer.h @@ -41,6 +41,9 @@ private: /// @returns a random entry from @p list static const building_desc_t* get_random_desc(vector_tpl& list, uint16 time, bool ignore_retire, climate cl); + static const building_desc_t* get_city_building_from_list(const vector_tpl &building_list, koord pos_origin, koord size, uint16 time, climate cl, uint32 clusters); + static const building_desc_t* get_city_building_from_list(const vector_tpl &building_list, int level, koord size, uint16 time, climate cl, uint32 clusters); + /// our game world static karte_ptr_t welt; @@ -78,13 +81,16 @@ public: static void fill_menu(tool_selector_t* tool_selector, building_desc_t::btype, waytype_t wt, sint16 sound_ok); /// @returns a random commercial building matching the requirements. - static const building_desc_t* get_commercial(int level, uint16 time, climate c, uint32 clusters = 0l); + static const building_desc_t* get_commercial(koord pos_origin, koord size, uint16 time, climate c, uint32 clusters = 0l); + static const building_desc_t* get_commercial(int level, koord size, uint16 time, climate c, uint32 clusters = 0l); /// @returns a random industrial building matching the requirements. - static const building_desc_t* get_industrial(int level, uint16 time, climate cl, uint32 clusters = 0); + static const building_desc_t* get_industrial(koord pos_origin, koord size, uint16 time, climate cl, uint32 clusters = 0); + static const building_desc_t* get_industrial(int level, koord size, uint16 time, climate cl, uint32 clusters = 0); /// @returns a random residential building matching the requirements. - static const building_desc_t* get_residential(int level, uint16 time, climate cl, uint32 clusters = 0); + static const building_desc_t* get_residential(koord pos_origin, koord size,uint16 time, climate cl, uint32 clusters = 0); + static const building_desc_t* get_residential(int level, koord size,uint16 time, climate cl, uint32 clusters = 0); /// @returns headquarters with level @p level (takes the first matching one) static const building_desc_t* get_headquarters(int level, uint16 time); @@ -122,7 +128,7 @@ public: * It will also take care of factories and foundations. * @param sp the player wanting to remove the building. */ - static void remove(player_t *player, gebaeude_t *gb); + static void remove(player_t *player, const gebaeude_t *gb); /** * Main function to build all non-traffic buildings, including factories. diff --git a/dataobj/settings.cc b/dataobj/settings.cc index 9f9191c45..d233ad777 100644 --- a/dataobj/settings.cc +++ b/dataobj/settings.cc @@ -154,6 +154,8 @@ settings_t::settings_t() : crossconnect_factor=33; #endif + max_level_leap_per_a_tile = 10; + /* minimum spacing between two factories */ min_factory_spacing = 6; max_factory_spacing = 40; @@ -1301,6 +1303,8 @@ void settings_t::parse_simuconf(tabfile_t& simuconf, sint16& disp_width, sint16& crossconnect_factor = contents.get_int("crossconnect_factories_percentage", crossconnect_factor ); electric_promille = contents.get_int("electric_promille", electric_promille ); + max_level_leap_per_a_tile = contents.get_int("max_level_leap_per_a_tile", max_level_leap_per_a_tile); + env_t::just_in_time = (uint8)contents.get_int("just_in_time", env_t::just_in_time); if( env_t::just_in_time > 2 ) { env_t::just_in_time = 2; // Range restriction. diff --git a/dataobj/settings.h b/dataobj/settings.h index 645fe19e9..e0f979efe 100644 --- a/dataobj/settings.h +++ b/dataobj/settings.h @@ -176,6 +176,9 @@ private: /* prissi: crossconnect all factories (like OTTD and similar games) */ sint16 crossconnect_factor; + /* THLeaderH: a parameter for the city building renovation. */ + uint8 max_level_leap_per_a_tile; + /** * Generate random pedestrians in the cities? * @@ -457,6 +460,8 @@ public: sint16 get_crossconnect_factor() const { return crossconnect_factor; } bool is_crossconnect_factories() const { return crossconnect_factories; } + uint8 get_max_level_leap_per_a_tile() const { return max_level_leap_per_a_tile; } + bool get_numbered_stations() const { return numbered_stations; } sint32 get_stadtauto_duration() const { return stadtauto_duration; } diff --git a/descriptor/building_desc.cc b/descriptor/building_desc.cc index beceb1768..23773acfc 100644 --- a/descriptor/building_desc.cc +++ b/descriptor/building_desc.cc @@ -240,3 +240,5 @@ sint32 building_desc_t::get_price(karte_t *world) const } return 0; } + +uint8 building_desc_t::city_building_max_size = 1; diff --git a/descriptor/building_desc.h b/descriptor/building_desc.h index bf5d0663c..5755a421a 100644 --- a/descriptor/building_desc.h +++ b/descriptor/building_desc.h @@ -221,6 +221,8 @@ private: tool_t *builder; + static uint8 city_building_max_size; + public: koord get_size(uint8 layout = 0) const { @@ -363,6 +365,8 @@ public: // Only meaningful for res, com, ind return is_city_building() ? extra_data : 0; } + + static uint8 get_city_building_max_size() { return city_building_max_size; } }; ENUM_BITSET(building_desc_t::flag_t) diff --git a/descriptor/reader/building_reader.cc b/descriptor/reader/building_reader.cc index 3361c675f..13fa4da0a 100644 --- a/descriptor/reader/building_reader.cc +++ b/descriptor/reader/building_reader.cc @@ -374,6 +374,14 @@ obj_desc_t * building_reader_t::read_node(FILE *fp, obj_node_info_t &node) desc->flags |= building_desc_t::FLAG_HAS_CURSOR; } + // calculate max size of city buildings. + if( desc->is_city_building() && desc->city_building_max_sizesize.x ) { + desc->city_building_max_size = desc->size.x; + } + if( desc->is_city_building() && desc->city_building_max_sizesize.y ) { + desc->city_building_max_size = desc->size.y; + } + // correct old station buildings ... if( version<=3 && ((uint8)desc->type >= building_desc_t::bahnhof || desc->type == building_desc_t::factory || desc->type == building_desc_t::depot) && desc->level==0 ) { DBG_DEBUG("building_reader_t::read_node()","old station building -> set level to 4"); diff --git a/obj/gebaeude.cc b/obj/gebaeude.cc index 997bd2984..d7e726247 100644 --- a/obj/gebaeude.cc +++ b/obj/gebaeude.cc @@ -766,12 +766,14 @@ void gebaeude_t::rdwr(loadsave_t *file) } // we try to replace citybuildings with their matching counterparts // if none are matching, we try again without climates and timeline! + // only 1x1 buildings can fill the empty tile to avoid overlap. + const koord single(1,1); switch(type) { case building_desc_t::city_res: { - const building_desc_t *bdsc = hausbauer_t::get_residential( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ) ); + const building_desc_t *bdsc = hausbauer_t::get_residential( level, single, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ) ); if(bdsc==NULL) { - bdsc = hausbauer_t::get_residential(level,0, MAX_CLIMATES ); + bdsc = hausbauer_t::get_residential(level, single, 0, MAX_CLIMATES ); } if( bdsc) { dbg->message("gebaeude_t::rwdr", "replace unknown building %s with residence level %i by %s",buf,level,bdsc->get_name()); @@ -782,9 +784,9 @@ void gebaeude_t::rdwr(loadsave_t *file) case building_desc_t::city_com: { - const building_desc_t *bdsc = hausbauer_t::get_commercial( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ) ); + const building_desc_t *bdsc = hausbauer_t::get_commercial( level, single, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ) ); if(bdsc==NULL) { - bdsc = hausbauer_t::get_commercial(level,0, MAX_CLIMATES ); + bdsc = hausbauer_t::get_commercial(level, single, 0, MAX_CLIMATES ); } if(bdsc) { dbg->message("gebaeude_t::rwdr", "replace unknown building %s with commercial level %i by %s",buf,level,bdsc->get_name()); @@ -795,11 +797,11 @@ void gebaeude_t::rdwr(loadsave_t *file) case building_desc_t::city_ind: { - const building_desc_t *bdsc = hausbauer_t::get_industrial( level, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ) ); + const building_desc_t *bdsc = hausbauer_t::get_industrial( level, single, welt->get_timeline_year_month(), welt->get_climate( get_pos().get_2d() ) ); if(bdsc==NULL) { - bdsc = hausbauer_t::get_industrial(level,0, MAX_CLIMATES ); + bdsc = hausbauer_t::get_industrial(level, single, 0, MAX_CLIMATES ); if(bdsc==NULL) { - bdsc = hausbauer_t::get_residential(level,0, MAX_CLIMATES ); + bdsc = hausbauer_t::get_residential(level, single, 0, MAX_CLIMATES ); } } if (bdsc) { diff --git a/simcity.cc b/simcity.cc index 082f92a75..42283b607 100644 --- a/simcity.cc +++ b/simcity.cc @@ -613,11 +613,18 @@ void stadt_t::add_gebaeude_to_stadt(const gebaeude_t* gb, bool ordered) buildings.remove(add_gb); } else { + uint16 level; + if( gb->is_city_building() ) { + const uint16 area = size.x*size.y; + level = tile->get_desc()->get_level()/area + 1; + } else { + level = tile->get_desc()->get_level() + 1; + } if( ordered ) { - buildings.insert_ordered(add_gb, tile->get_desc()->get_level() + 1, compare_gebaeude_pos); + buildings.insert_ordered(add_gb, level, compare_gebaeude_pos); } else { - buildings.append(add_gb, tile->get_desc()->get_level() + 1); + buildings.append(add_gb, level); } } add_gb->set_stadt(this); @@ -1851,10 +1858,12 @@ void stadt_t::step_passagiere() const gebaeude_t* gb = buildings[step_count]; // prissi: since now backtravels occur, we damp the numbers a little + const koord gb_size = gb->get_tile()->get_desc()->get_size(); + const uint16 area_factor = gb->is_city_building() ? gb_size.x*gb_size.y : 1; const uint32 num_pax = (ispass) ? - (gb->get_tile()->get_desc()->get_level() + 6) >> 2 : - (gb->get_tile()->get_desc()->get_mail_level() + 8) >> 3 ; + (gb->get_tile()->get_desc()->get_level() / area_factor + 6) >> 2 : + (gb->get_tile()->get_desc()->get_mail_level() / area_factor + 8) >> 3 ; // create pedestrians in the near area? if (welt->get_settings().get_random_pedestrians() && ispass) { @@ -2870,7 +2879,71 @@ int stadt_t::orient_city_building(const koord k, const building_desc_t *h ) return -1; } - +/* + * get available building sizes to renovate + * + * Tiles must be nature or a city building. + * Tile height must be same. If it is slope, it is treated as it is raised. + */ +void stadt_t::get_available_building_size(const koord k, vector_tpl &sizes) const { + sizes.clear(); + const uint8 LEN_LIM = building_desc_t::get_city_building_max_size(); + const grund_t* gr_origin = welt->lookup_kartenboden(k); + assert(gr_origin); + const gebaeude_t* gb_origin = gr_origin->find(); + assert(gb_origin); + const koord dim_origin = gb_origin->get_tile()->get_desc()->get_size(); + const uint8 layout_origin = gb_origin->get_tile()->get_layout(); + for(uint8 w=(layout_origin&1)?dim_origin.y:dim_origin.x; w<=LEN_LIM; w++) { + for(uint8 h=(layout_origin&1)?dim_origin.x:dim_origin.y; h<=LEN_LIM; h++) { + bool check_continue = true; + sint8 height = -100; + for(uint8 x=0; xlookup_kartenboden(p); + // the tile must be nature or a city building. + if( !gr || !(gr->ist_natur() || (gr->find() && gr->find()->is_city_building()))) { + check_continue = false; + break; + } + // the tile must be in the same height as others. + sint8 tile_height; + const slope_t::type hang = welt->recalc_natural_slope(p, tile_height); + if(hang!=slope_t::flat) { + tile_height ++; + } + if(height!=-100 && height!=tile_height) { + check_continue = false; + break; + } + height = tile_height; + // buildings in the area must not be in the outside of the area. + const sint8 x_off = x==0 ? -1 : (x==w-1 ? 1 : 0); + const sint8 y_off = y==0 ? -1 : (y==h-1 ? 1 : 0); + const gebaeude_t* gb = gr->find(); + if(gb && (x==0 || y==0 || x==w-1 || y==h-1)) { + const grund_t* neighbor_gr = welt->lookup_kartenboden(k+koord(x_off,y_off)); + if(neighbor_gr) { + const gebaeude_t* neighbor_gb = neighbor_gr->find(); + if(gb==neighbor_gb) { + check_continue = false; + break; + } + } + } + } + } + if(check_continue) { + koord s(w,h); + sizes.append(s); + } + } + } +} void stadt_t::build_city_building(const koord k) { @@ -2927,23 +3000,24 @@ void stadt_t::build_city_building(const koord k) // Find a house to build const building_desc_t* h = NULL; + const koord size_single(1,1); if (sum_commercial > sum_industrial && sum_commercial > sum_residential) { - h = hausbauer_t::get_commercial(0, current_month, cl, neighbor_building_clusters); + h = hausbauer_t::get_commercial(0, size_single, current_month, cl, neighbor_building_clusters); if (h != NULL) { arb += (h->get_level()+1) * 20; } } if (h == NULL && sum_industrial > sum_residential && sum_industrial > sum_commercial) { - h = hausbauer_t::get_industrial(0, current_month, cl, neighbor_building_clusters); + h = hausbauer_t::get_industrial(0, size_single, current_month, cl, neighbor_building_clusters); if (h != NULL) { arb += (h->get_level()+1) * 20; } } if (h == NULL && sum_residential > sum_industrial && sum_residential > sum_commercial) { - h = hausbauer_t::get_residential(0, current_month, cl, neighbor_building_clusters); + h = hausbauer_t::get_residential(0, size_single, current_month, cl, neighbor_building_clusters); if (h != NULL) { // will be aligned next to a street won += (h->get_level()+1) * 10; @@ -2960,17 +3034,11 @@ void stadt_t::build_city_building(const koord k) void stadt_t::renovate_city_building(gebaeude_t *gb) { - const building_desc_t::btype alt_typ = gb->get_tile()->get_desc()->get_type(); if( !gb->is_city_building() ) { return; // only renovate res, com, ind } - if( gb->get_tile()->get_desc()->get_x()*gb->get_tile()->get_desc()->get_y() != 1 ) { - return; // too big ... - } - // Now we are sure that this is a city building - const int level = gb->get_tile()->get_desc()->get_level(); const koord k = gb->get_pos().get_2d(); // Divide unemployed by 4, because it counts towards commercial and industrial, @@ -2991,9 +3059,19 @@ void stadt_t::renovate_city_building(gebaeude_t *gb) // Run through orthogonal neighbors (only) looking for which cluster to build // This is a bitmap -- up to 32 clustering types are allowed. + vector_tpl orthogonal_neighbors; + const building_desc_t* gb_desc = gb->get_tile()->get_desc(); + for(sint8 x=0; xget_size().x; x++) { + orthogonal_neighbors.append(k+koord(x,-1)); + orthogonal_neighbors.append(k+koord(x,gb_desc->get_size().y)); + } + for(sint8 y=0; yget_size().y; y++) { + orthogonal_neighbors.append(k+koord(-1,y)); + orthogonal_neighbors.append(k+koord(gb_desc->get_size().x,y)); + } uint32 neighbor_building_clusters = 0; - for (int i = 0; i < 4; i++) { - grund_t* gr = welt->lookup_kartenboden(k + neighbors[i]); + for (uint16 i=0; ilookup_kartenboden(orthogonal_neighbors[i]); if (gr && gr->get_typ() == grund_t::fundament && gr->obj_bei(0)->get_typ() == obj_t::gebaeude) { // We have a building as a neighbor... gebaeude_t const* const gb = obj_cast(gr->first_obj()); @@ -3008,32 +3086,48 @@ void stadt_t::renovate_city_building(gebaeude_t *gb) building_desc_t::btype want_to_have = building_desc_t::unknown; int sum = 0; + // get available building sizes. + vector_tpl available_sizes; + get_available_building_size(k, available_sizes); + const uint8 size_offset = simrand(available_sizes.get_count()); + // try to build const building_desc_t* h = NULL; + koord selected_dim; if (sum_commercial > sum_industrial && sum_commercial > sum_residential) { // we must check, if we can really update to higher level ... - const int try_level = (alt_typ == building_desc_t::city_com ? level + 1 : level); - h = hausbauer_t::get_commercial(try_level, current_month, cl, neighbor_building_clusters); - if( h != NULL && h->get_level() >= try_level ) { - want_to_have = building_desc_t::city_com; - sum = sum_commercial; + for(uint8 i=0; i sum_commercial && sum_industrial > sum_residential) || (sum_commercial > sum_residential && want_to_have == building_desc_t::unknown) ) { // we must check, if we can really update to higher level ... - const int try_level = (alt_typ == building_desc_t::city_ind ? level + 1 : level); - h = hausbauer_t::get_industrial(try_level , current_month, cl, neighbor_building_clusters); - if( h != NULL && h->get_level() >= try_level ) { - want_to_have = building_desc_t::city_ind; - sum = sum_industrial; + for(uint8 i=0; isum_industrie && sum_wohnung>sum_gewerbe if( want_to_have == building_desc_t::unknown ) { // we must check, if we can really update to higher level ... + bool found = false; + /* const int try_level = (alt_typ == building_desc_t::city_res ? level + 1 : level); h = hausbauer_t::get_residential(try_level, current_month, cl, neighbor_building_clusters); if( h != NULL && h->get_level() >= try_level ) { @@ -3043,18 +3137,34 @@ void stadt_t::renovate_city_building(gebaeude_t *gb) else { h = NULL; } + */ + for(uint8 i=0; i 0 && h != NULL ) { // DBG_MESSAGE("stadt_t::renovate_city_building()", "renovation at %i,%i (%i level) of typ %i to typ %i with desire %i", k.x, k.y, alt_typ, want_to_have, sum); - int rotation = 0; - if( h->get_all_layouts()>1 ) { + int rotation = h->get_size().x==selected_dim.x ? 0 : 1; + if( h->get_all_layouts()>1 && h->get_size()==koord(1,1) ) { // check for pavement int streetdir = 0; for( int i = 0; i < 4; i++ ) { @@ -3098,17 +3208,52 @@ void stadt_t::renovate_city_building(gebaeude_t *gb) } } - switch(alt_typ) { - case building_desc_t::city_res: won -= level * 10; break; - case building_desc_t::city_com: arb -= level * 20; break; - case building_desc_t::city_ind: arb -= level * 20; break; - default: break; + // we stock the removed buildings. + + vector_tpl removed_buildings; + for(uint8 x=0; x<(rotation&1?h->get_size().y:h->get_size().x); x++) { + for(uint8 y=0; y<(rotation&1?h->get_size().x:h->get_size().y); y++) { + const grund_t* gr = welt->lookup_kartenboden(k+koord(x,y)); + assert(gr); + const gebaeude_t* bldg = gr->find(); + if(bldg) { + const building_desc_t* desc = bldg->get_tile()->get_desc(); + removed_building rb; + rb.desc = desc; + rb.pos = bldg->get_pos(); + rb.rotation = bldg->get_tile()->get_layout(); + removed_buildings.append(rb); + hausbauer_t::remove(NULL, bldg); + } + } + } + + const koord3d pos = welt->lookup_kartenboden(k)->get_pos(); + gebaeude_t* new_gb = hausbauer_t::build(NULL, pos, rotation, h); + // Check that all tiles are same height. If it is different, we remove that. + gebaeude_t* checked_gb = check_tiles_height(new_gb, k, rotation); + if(!checked_gb) { + // height was different. Let's recover. + for(uint8 j=0; jget_level(); + switch(removed_buildings[j].desc->get_type()) { + case building_desc_t::city_res: won -= level * 10; break; + case building_desc_t::city_com: arb -= level * 20; break; + case building_desc_t::city_ind: arb -= level * 20; break; + default: break; + } } - // exchange building; try to face it to street in front - gb->mark_images_dirty(); - gb->set_tile( h->get_tile(rotation, 0, 0), true ); - welt->lookup_kartenboden(k)->calc_image(); - update_gebaeude_from_stadt(gb); switch(want_to_have) { case building_desc_t::city_res: won += h->get_level() * 10; break; @@ -3119,6 +3264,54 @@ void stadt_t::renovate_city_building(gebaeude_t *gb) } } +/* + * a subroutine of renovate_city_buiding + * If successfully built, return the pointer of building. + * If failed, return NULL. + */ +gebaeude_t* stadt_t::check_tiles_height(gebaeude_t* building, koord pos, uint8 layout) { + // We check whether all tiles are same height because we sometimes fail to estimate the height. + const building_desc_t* desc = building->get_tile()->get_desc(); + bool height_check_approved = true; + sint8 tile_height = -100; + for(uint8 x=0; x<(layout&1?desc->get_size().y:desc->get_size().x); x++) { + for(uint8 y=0; y<(layout&1?desc->get_size().x:desc->get_size().y); y++) { + const grund_t* gr = welt->lookup_kartenboden(pos+koord(x,y)); + if(!gr) { + dbg->error("stadt_t::check_height_and_rebuild()", "ground not found! pos:%s", (pos+koord(x,y)).get_str()); + } + if(tile_height!=-100 && tile_height!=gr->get_pos().z) { + // height is different! + height_check_approved = false; + break; + } + tile_height = gr->get_pos().z; + } + } + if(height_check_approved) { + // all tiles are same height. + return building; + } + dbg->message("stadt_t::check_tiles_height()", "height is different. we remove building at pos:%s", pos.get_str()); + // height is different. + // remove all buildings in the area. + for(uint8 x=0; x<(layout&1?desc->get_size().y:desc->get_size().x); x++) { + for(uint8 y=0; y<(layout&1?desc->get_size().x:desc->get_size().y); y++) { + const grund_t* gr = welt->lookup_kartenboden(pos+koord(x,y)); + if(!gr) { + dbg->error("stadt_t::check_height_and_rebuild()", "ground not found! pos:%s", (pos+koord(x,y)).get_str()); + } + const gebaeude_t* bldg = gr->find(); + if(bldg) { + if(!bldg->is_city_building()) { + dbg->error("stadt_t::check_height_and_rebuild()", "building is not a city building! pos:%s", (pos+koord(x,y)).get_str()); + } + hausbauer_t::remove(NULL, bldg); + } + } + } + return NULL; +} #ifdef DESTINATION_CITYCARS void stadt_t::generate_private_cars(koord pos, koord target) @@ -3414,9 +3607,11 @@ void stadt_t::build() if( !buildings.empty() && simrand(100) <= renovation_percentage ) { // try to find a public owned building for( uint8 i=0; i<4; i++ ) { + // we must give gebaeude of the original position. gebaeude_t* const gb = pick_any(buildings); if( player_t::check_owner(gb->get_owner(),NULL) ) { - renovate_city_building(gb); + // we must give gebaeude of the original position. + renovate_city_building(gb->get_first_tile()); break; } } diff --git a/simcity.h b/simcity.h index fb63749d4..edc22cd06 100644 --- a/simcity.h +++ b/simcity.h @@ -383,6 +383,17 @@ private: void build_city_building(koord pos); void renovate_city_building(gebaeude_t *gb); + class removed_building { + public: + const building_desc_t* desc; + koord3d pos; + int rotation; + }; + + // sub-routines of renovate_city_building + void get_available_building_size(const koord k, vector_tpl &sizes) const; + gebaeude_t* check_tiles_height(gebaeude_t* building, koord pos, uint8 layout); + #ifdef DESTINATION_CITYCARS sint16 number_of_cars; // allowed number of cars to spawn per month void generate_private_cars(koord pos, koord target);