diff --git a/dataobj/settings.cc b/dataobj/settings.cc index 41c34a306..dc2ab51d2 100644 --- a/dataobj/settings.cc +++ b/dataobj/settings.cc @@ -255,6 +255,7 @@ settings_t::settings_t() : cst_depot_road=-130000; cst_depot_ship=-250000; cst_depot_air=-500000; + cst_multiply_merge_halt=-50000; // alter landscape cst_buy_land=-10000; cst_alter_land=-100000; @@ -644,6 +645,10 @@ void settings_t::rdwr(loadsave_t *file) file->rdwr_longlong(cst_make_public_months); } + if( file->get_version() > 120008 ) { + file->rdwr_longlong(cst_multiply_merge_halt); + } + // wayfinder file->rdwr_long(way_count_straight ); file->rdwr_long(way_count_curve ); @@ -1348,6 +1353,8 @@ void settings_t::parse_simuconf(tabfile_t& simuconf, sint16& disp_width, sint16& cst_depot_road = contents.get_int64("cost_depot_road", cst_depot_road/(-100) ) * -100; cst_depot_ship = contents.get_int64("cost_depot_ship", cst_depot_ship/(-100) ) * -100; + cst_multiply_merge_halt = contents.get_int64("cost_multiply_merge_halt", cst_multiply_merge_halt/(-100) ) * -100; + // alter landscape cst_buy_land = contents.get_int64("cost_buy_land", cst_buy_land/(-100) ) * -100; cst_alter_land = contents.get_int64("cost_alter_land", cst_alter_land/(-100) ) * -100; diff --git a/dataobj/settings.h b/dataobj/settings.h index abe837580..55d31abe8 100644 --- a/dataobj/settings.h +++ b/dataobj/settings.h @@ -302,6 +302,9 @@ public: sint64 cst_depot_ship; sint64 cst_depot_air; + // cost to merge station + sint64 cst_multiply_merge_halt; + // alter landscape sint64 cst_buy_land; sint64 cst_alter_land; diff --git a/dataobj/settings.h.gch b/dataobj/settings.h.gch new file mode 100644 index 000000000..7ec7dc255 Binary files /dev/null and b/dataobj/settings.h.gch differ diff --git a/script/api/changelog.h.gch b/script/api/changelog.h.gch new file mode 100644 index 000000000..b0968dfd9 Binary files /dev/null and b/script/api/changelog.h.gch differ diff --git a/simhalt.cc b/simhalt.cc index 4d4630417..600d5aa4c 100644 --- a/simhalt.cc +++ b/simhalt.cc @@ -224,6 +224,24 @@ koord3d haltestelle_t::get_basis_pos3d() const return tiles.front().grund->get_pos(); } +/* Get center position of this station + * It is the avarage of all tiles' coordinate weighed by level of the building */ +koord haltestelle_t::get_center_pos() const +{ + koord center_pos; + sint32 level_sum; + center_pos = koord(); + level_sum = 0; + FOR(slist_tpl, const& i, tiles) { + if( gebaeude_t* const gb = i.grund->find() ) { + sint16 lv; + lv = gb->get_tile()->get_desc()->get_level(); + center_pos += gb->get_pos().get_2d() * lv; + level_sum += lv; + } + } + return center_pos/level_sum; +} /** * Station factory method. Returns handles instead of pointers. @@ -1021,7 +1039,7 @@ void haltestelle_t::verbinde_fabriken() FOR(slist_tpl, const& i, tiles) { koord const p = i.grund->get_pos().get_2d(); - int const cov = welt->get_settings().get_station_coverage(); + uint16 const cov = welt->get_settings().get_station_coverage(); FOR(vector_tpl, const fab, fabrik_t::sind_da_welche(p - koord(cov, cov), p + koord(cov, cov))) { if(!fab_list.is_contained(fab)) { // water factories can only connect to docks @@ -2356,6 +2374,99 @@ void haltestelle_t::make_public_and_join( player_t *player ) } +// merge stop +void haltestelle_t::merge_halt( player_t *player, halthandle_t halt_merged ) +{ + player_t *const public_owner = welt->get_public_player(); + + // process every tile of stop + slist_tpl joining; + FOR(slist_tpl, const& i, tiles) { + grund_t* const gr = i.grund; + gebaeude_t* gb = gr->find(); + if( gb ) { + gb->set_flag(obj_t::dirty); + } + + // search for stops to join, starting with this tile + const planquadrat_t *pl = welt->access(gr->get_pos().get_2d()); + for( uint8 i=0; i < pl->get_boden_count(); i++ ) { + halthandle_t my_halt = pl->get_boden_bei(i)->get_halt(); + if( my_halt.is_bound() && !joining.is_contained(my_halt) ) { + joining.append(my_halt); + } + } + } + + // search for stops merged to + FOR(slist_tpl, const& i, halt_merged->get_tiles()) { + grund_t* const gr = i.grund; + gebaeude_t* gb = gr->find(); + if( gb ) { + gb->set_flag(obj_t::dirty); + } + + const planquadrat_t *pl2 = welt->access(gr->get_pos().get_2d()); + for( uint8 i=0; i < pl2->get_boden_count(); i++ ) { + halthandle_t my_halt = pl2->get_boden_bei(i)->get_halt(); + if( my_halt.is_bound() && !joining.is_contained(my_halt) ) { + joining.append(my_halt); + } + } + } + + // set name to name of first stop + if( !joining.empty() ) { + set_name( joining.front()->get_name()); + } + + while( !joining.empty() ) { + // join this halt with me + halthandle_t halt = joining.remove_first(); + + // now with the second stop + while( halt.is_bound() && halt!=self ) { + // add statistics + for( int month=0; monthfinancial_history[month][type]; + halt->financial_history[month][type] = 0; // to avoid counting twice + } + } + + // we always take the first remaining tile and transfer it => more safe + koord3d t = halt->get_basis_pos3d(); + grund_t *gr = welt->lookup(t); + + // transfer tiles to us + halt->rem_grund(gr); + add_grund(gr); + // and check for existence + if(!halt->existiert_in_welt()) { + // transfer goods + halt->transfer_goods(self); + + // rebuild connections of all linked halts + // otherwise these halts would lose connections and freight might get lost + // (until complete rebuild_connections task is finished) + halt->rebuild_linked_connections(); + + destroy(halt); + } + } + } + + // tell the world of it ... + if( player != public_owner && env_t::networkmode ) { + cbuffer_t buf; + buf.printf( translator::translate("%s at (%i,%i) now merged to %s at (%i,%i)."), halt_merged->get_name(), halt_merged->get_basis_pos().x, halt_merged->get_basis_pos().y, get_name(), get_basis_pos().x, get_basis_pos().y ); + welt->get_message()->add_message( buf, get_basis_pos(), message_t::ai, PLAYER_FLAG|player->get_player_nr(), IMG_EMPTY ); + } + + recalc_station_type(); +} + + void haltestelle_t::transfer_goods(halthandle_t halt) { if (!self.is_bound() || !halt.is_bound()) { @@ -2984,7 +3095,7 @@ bool haltestelle_t::add_grund(grund_t *gr, bool relink_factories) // appends this to the ground // after that, the surrounding ground will know of this station bool insert_unsorted = !relink_factories; - int const cov = welt->get_settings().get_station_coverage(); + uint16 const cov = welt->get_settings().get_station_coverage(); for (int y = -cov; y <= cov; y++) { for (int x = -cov; x <= cov; x++) { koord p=pos+koord(x,y); @@ -3119,7 +3230,7 @@ bool haltestelle_t::rem_grund(grund_t *gr) pl->get_kartenboden()->set_flag(grund_t::dirty); } - int const cov = welt->get_settings().get_station_coverage(); + uint16 const cov = welt->get_settings().get_station_coverage(); for (int y = -cov; y <= cov; y++) { for (int x = -cov; x <= cov; x++) { planquadrat_t *pl = welt->access( gr->get_pos().get_2d()+koord(x,y) ); @@ -3343,3 +3454,32 @@ void haltestelle_t::release_factory_links() } fab_list.clear(); } + +/* check if this tile is covered by this station */ +bool haltestelle_t::is_pos_covered(const koord &pos) const +{ + uint16 const cov = welt->get_settings().get_station_coverage(); + FOR(slist_tpl, const& i, tiles) { + if ( gebaeude_t* const gb = i.grund->find() ) { + if ( koord_distance(gb->get_pos(), pos) <= cov ) + { + return true; + } + } + } + return false; +} + +/* check if the station is covered by this */ +bool haltestelle_t::is_halt_covered(const halthandle_t &halt) const +{ + FOR(slist_tpl, const& i, halt->get_tiles()) { + if ( gebaeude_t* const gb = i.grund->find() ) { + if ( is_pos_covered( gb->get_pos().get_2d() ) ) + { + return true; + } + } + } + return false; +} diff --git a/simhalt.h b/simhalt.h index a0f581630..bb366c727 100644 --- a/simhalt.h +++ b/simhalt.h @@ -429,6 +429,8 @@ public: void make_public_and_join( player_t *player ); + void merge_halt( player_t *player, halthandle_t halt_merged ); + vector_tpl const& get_pax_connections() const { return all_links[goods_manager_t::INDEX_PAS].connections; } vector_tpl const& get_mail_connections() const { return all_links[goods_manager_t::INDEX_MAIL].connections; } @@ -594,6 +596,7 @@ public: koord get_init_pos() const { return init_pos; } koord get_basis_pos() const; koord3d get_basis_pos3d() const; + koord get_center_pos() const; /* return the closest square that belongs to this halt * @author prissi @@ -809,6 +812,11 @@ public: */ static void init_markers(); + /* + * check it is in the station coverage + */ + bool is_pos_covered (const koord &pos) const; + bool is_halt_covered (const halthandle_t &halt) const; }; ENUM_BITSET(haltestelle_t::stationtyp) diff --git a/simhalt.h.gch b/simhalt.h.gch new file mode 100644 index 000000000..ea38f301a Binary files /dev/null and b/simhalt.h.gch differ diff --git a/simmenu.cc b/simmenu.cc index 1a2d94a25..cc80883c6 100644 --- a/simmenu.cc +++ b/simmenu.cc @@ -120,6 +120,7 @@ tool_t *create_general_tool(int toolnr) case TOOL_CHANGE_WATER_HEIGHT: tool = new tool_change_water_height_t(); break; case TOOL_SET_CLIMATE: tool = new tool_set_climate_t(); break; case TOOL_ROTATE_BUILDING: tool = new tool_rotate_building_t(); break; + case TOOL_MERGE_STOP: tool = new tool_merge_stop_t(); break; default: dbg->error("create_general_tool()","cannot satisfy request for general_tool[%i]!",toolnr); return NULL; } diff --git a/simmenu.h b/simmenu.h index 9a6f46f95..de3a4ba92 100644 --- a/simmenu.h +++ b/simmenu.h @@ -73,6 +73,7 @@ enum { TOOL_CHANGE_WATER_HEIGHT, TOOL_SET_CLIMATE, TOOL_ROTATE_BUILDING, + TOOL_MERGE_STOP, GENERAL_TOOL_COUNT, GENERAL_TOOL = 0x1000 }; diff --git a/simmenu.h.gch b/simmenu.h.gch new file mode 100644 index 000000000..e837aff16 Binary files /dev/null and b/simmenu.h.gch differ diff --git a/simres.d b/simres.d new file mode 100644 index 000000000..1369acbe0 --- /dev/null +++ b/simres.d @@ -0,0 +1 @@ +build/default/simres.o: simres.rc simversion.h diff --git a/simtool.cc b/simtool.cc index 2ef8def6a..2ebf70878 100644 --- a/simtool.cc +++ b/simtool.cc @@ -6200,7 +6200,6 @@ bool tool_daynight_level_t::init( player_t * ) { } - /* make all tiles of this player a public stop * if this player is public, make all connected tiles a public stop */ bool tool_make_stop_public_t::init( player_t * ) @@ -6370,6 +6369,80 @@ const char *tool_make_stop_public_t::work( player_t *player, koord3d p ) } +/* merge stop */ +image_id tool_merge_stop_t::get_marker_image() +{ + return cursor; +} + +uint8 tool_merge_stop_t::is_valid_pos( player_t *player, const koord3d &pos, const char *&error, const koord3d &) +{ + grund_t *bd = welt->lookup(pos); + if (bd==NULL) { + error = ""; + return 0; + } + // check halt ownership + halthandle_t h = haltestelle_t::get_halt(pos,player); + if( h.is_bound() && !player_t::check_owner( player, h->get_owner() ) ) { + error = "Das Feld gehoert\neinem anderen Spieler\n"; + return 0; + } + // check for halt on the tile + if( h.is_bound() && ( bd->is_halt() || (h->get_station_type()&haltestelle_t::dock && bd->is_water()) ) ) { + return 2; + } + error = NOTICE_UNSUITABLE_GROUND; + return 0; +} + +void tool_merge_stop_t::mark_tiles( player_t *player, const koord3d &start, const koord3d &end ) +{ + halt_be_merged_from = halthandle_t(); + halt_be_merged_to = halthandle_t(); + halt_be_merged_from = haltestelle_t::get_halt(start,player); + halt_be_merged_to = haltestelle_t::get_halt(end,player); + sint32 dist = (sint32)koord_distance( halt_be_merged_from->get_center_pos(), halt_be_merged_to->get_center_pos() ); + sint64 workcost = 0; + if ( !halt_be_merged_from->is_halt_covered( halt_be_merged_to ) ) { + workcost = -welt->scale_with_month_length( dist * welt->get_settings().cst_multiply_merge_halt); + } + if( dist>0 ) { + win_set_static_tooltip( tooltip_with_price("Building costs estimates", workcost) ); + } +} + +const char *tool_merge_stop_t::do_work( player_t *player, const koord3d &last_pos, const koord3d &pos) +{ + player_t *const psplayer = welt->get_public_player(); + bool const giveaway = player != psplayer; + halt_be_merged_from = halthandle_t(); + halt_be_merged_to = halthandle_t(); + halt_be_merged_from = haltestelle_t::get_halt(last_pos,player); + halt_be_merged_to = haltestelle_t::get_halt(pos,player); + + // check funds + sint32 dist = (sint32)koord_distance( halt_be_merged_from->get_center_pos(), halt_be_merged_to->get_center_pos() ); + sint64 workcost = 0; + if ( !halt_be_merged_from->is_halt_covered( halt_be_merged_to ) ) { + workcost = -welt->scale_with_month_length( dist * welt->get_settings().cst_multiply_merge_halt); + } + if( giveaway && !player->can_afford(workcost) ) { + return NOTICE_INSUFFICIENT_FUNDS; + } + + player_t::book_construction_costs(player, -workcost, pos.get_2d(), ignore_wt); + + if( ( halt_be_merged_to.is_bound() && halt_be_merged_to->get_owner() != psplayer && player_t::check_owner(halt_be_merged_to->get_owner(), player) ) && + ( halt_be_merged_from.is_bound() && halt_be_merged_from->get_owner() != psplayer && player_t::check_owner(halt_be_merged_from->get_owner(), player) ) ) { + // merge stop + halt_be_merged_to->merge_halt(player, halt_be_merged_from); + return NULL; + } + + // nothing to do + return NULL; +} bool tool_show_trees_t::init( player_t * ) { diff --git a/simtool.h b/simtool.h index a9bb98707..3d4a9a054 100644 --- a/simtool.h +++ b/simtool.h @@ -613,6 +613,23 @@ public: }; +/* merge stop */ +class tool_merge_stop_t : public two_click_tool_t { +private: + halthandle_t halt_be_merged_from; + halthandle_t halt_be_merged_to; +public: + tool_merge_stop_t() : two_click_tool_t(TOOL_MERGE_STOP | GENERAL_TOOL) {} + char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("merge stop"); } + bool is_init_network_save() const OVERRIDE { return true; } +private: + char const* do_work(player_t*, koord3d const&, koord3d const&) OVERRIDE; + void mark_tiles(player_t*, koord3d const&, koord3d const&) OVERRIDE; + uint8 is_valid_pos(player_t*, koord3d const&, char const*&, koord3d const&) OVERRIDE; + image_id get_marker_image() OVERRIDE; +}; + + // internal tool: show error message at specific coordinate // used for scenario error messages send by server class tool_error_message_t : public tool_t {