diff --git a/descriptor/factory_desc.h b/descriptor/factory_desc.h index 59576cb28a..2137744878 100644 --- a/descriptor/factory_desc.h +++ b/descriptor/factory_desc.h @@ -235,6 +235,11 @@ class factory_desc_t : public obj_desc_t { sint8 sound_id; uint32 sound_interval; + // Extended pak: automatic upgrade when retiring + uint16 upgrade_probability; // 0 = never upgrade; 1-10000 = chance out of 10000 + char* upgrade_to_name; // temporary during loading; freed after resolution + const factory_desc_t* upgrade_to; // resolved target, NULL = no upgrade + public: const char *get_name() const { return get_building()->get_name(); } const char *get_copyright() const { return get_building()->get_copyright(); } @@ -300,6 +305,9 @@ class factory_desc_t : public obj_desc_t { sint8 get_sound() const { return sound_id; } uint32 get_sound_interval_ms() const { return sound_interval; } + uint16 get_upgrade_probability() const { return upgrade_probability; } + const factory_desc_t* get_upgrade_to() const { return upgrade_to; } + void calc_checksum(checksum_t *chk) const; }; diff --git a/descriptor/reader/factory_reader.cc b/descriptor/reader/factory_reader.cc index f13f916195..360aa71fdb 100644 --- a/descriptor/reader/factory_reader.cc +++ b/descriptor/reader/factory_reader.cc @@ -307,6 +307,9 @@ obj_desc_t *factory_reader_t::read_node(FILE *fp, obj_node_info_t &node) desc->sound_id = NO_SOUND; desc->sound_interval = 0xFFFFFFFFul; desc->smokerotations = 0; + desc->upgrade_probability = 0; + desc->upgrade_to_name = NULL; + desc->upgrade_to = NULL; typedef factory_desc_t::site_t site_t; if(version == 5) { @@ -460,6 +463,23 @@ obj_desc_t *factory_reader_t::read_node(FILE *fp, obj_node_info_t &node) desc->mail_demand = 65535; } + // Extended pak fields (appended after any standard version block) + if( extended ) { + if( extended_version > 1 ) { + dbg->fatal("factory_reader_t::read_node()", "Incompatible Extended pak version %i", extended_version); + } + if( extended_version >= 1 ) { + desc->upgrade_probability = decode_uint16(p); + const uint8 len = decode_uint8(p); + if( len > 0 ) { + char *name = new char[len + 1]; + for( uint8 i = 0; i < len; i++ ) { name[i] = decode_sint8(p); } + name[len] = '\0'; + desc->upgrade_to_name = name; + } + } + } + DBG_DEBUG("factory_reader_t::read_node()", "version=%i, place=%i, productivity=%i, suppliers=%i, products=%i, fields=%i, range=%i, level=%i" "Demands: pax=%i / mail=%i / electric=%i," @@ -509,6 +529,9 @@ DBG_MESSAGE("vehicle_reader_t::register_obj()","old sound %i to %i",old_id,desc- } +// Factories that have an upgrade_to_name needing resolution after all descs are loaded. +static vector_tpl pending_upgrade_resolution; + void factory_reader_t::register_obj(obj_desc_t *&data) { factory_desc_t* desc = static_cast(data); @@ -516,10 +539,25 @@ void factory_reader_t::register_obj(obj_desc_t *&data) desc->electricity_producer = ( fab_name_len>11 && (strcmp(desc->get_name()+fab_name_len-9, "kraftwerk")==0 || strcmp(desc->get_name()+fab_name_len-11, "Power Plant")==0) ); desc->correct_smoke(); factory_builder_t::register_desc(desc); + if( desc->upgrade_to_name ) { + pending_upgrade_resolution.append(desc); + } } bool factory_reader_t::successfully_loaded() const { + // Resolve upgrade targets now that all factory descs are registered. + FOR(vector_tpl, desc, pending_upgrade_resolution) { + desc->upgrade_to = factory_builder_t::get_desc(desc->upgrade_to_name); + if( !desc->upgrade_to ) { + dbg->warning("factory_reader_t::successfully_loaded()", + "upgrade target '%s' not found for factory '%s'", + desc->upgrade_to_name, desc->get_name()); + } + delete[] desc->upgrade_to_name; + desc->upgrade_to_name = NULL; + } + pending_upgrade_resolution.clear(); return factory_builder_t::successfully_loaded(); } diff --git a/simfab.cc b/simfab.cc index 1f591ea754..3d12479908 100644 --- a/simfab.cc +++ b/simfab.cc @@ -2827,14 +2827,26 @@ void fabrik_t::new_month() const uint16 timeline_month = welt->get_timeline_year_month(); // This will be 0 if timeline is disabled. const uint16 retire_month = desc->get_building()->get_retire_year_month(); const uint32 latest_retire_month = retire_month + (12 * welt->get_settings().get_factory_max_years_obsolete());//welt->get_settings().get_factory_max_years_obsolete()); - if(welt->get_settings().is_close_old_factory() && !no_close_factory && !no_close_factory && timeline_month > retire_month) + if(welt->get_settings().is_close_old_factory() && !no_close_factory && timeline_month > retire_month) { if(latest_retire_month <= timeline_month || simrand(latest_retire_month - timeline_month) == 0) { + // Check whether this factory upgrades to a successor instead of simply closing. + pending_upgrade = NULL; + const factory_desc_t* upgrade_desc = desc->get_upgrade_to(); + if( upgrade_desc && desc->get_upgrade_probability() > 0 + && simrand(10000) < desc->get_upgrade_probability() ) { + pending_upgrade = upgrade_desc; + } welt->closed_factories_this_month.append(this); cbuffer_t buf; - buf.printf( translator::translate("Factory %s has closed."), get_name()); - welt->get_message()->add_message( (const char *)buf, get_pos().get_2d(), message_t::warnings, CITY_KI, get_desc()->get_building()->get_tile(0)->get_background(0, 0, 0)); + if( pending_upgrade ) { + buf.printf( translator::translate("Factory %s has been upgraded."), get_name()); + welt->get_message()->add_message( (const char *)buf, get_pos().get_2d(), message_t::industry, CITY_KI, get_desc()->get_building()->get_tile(0)->get_background(0, 0, 0)); + } else { + buf.printf( translator::translate("Factory %s has closed."), get_name()); + welt->get_message()->add_message( (const char *)buf, get_pos().get_2d(), message_t::warnings, CITY_KI, get_desc()->get_building()->get_tile(0)->get_background(0, 0, 0)); + } } else { cbuffer_t buf; buf.printf( translator::translate("Factory %s is retired! Close soon!"), get_name()); diff --git a/simfab.h b/simfab.h index ac22ac2cdc..4de6cb4e42 100644 --- a/simfab.h +++ b/simfab.h @@ -481,6 +481,7 @@ class fabrik_t * if this flag is true, this factory cannot close even after retire year */ bool no_close_factory=false; + const factory_desc_t* pending_upgrade=NULL; // set when upgrading instead of closing /** * the shipment size @@ -742,6 +743,7 @@ class fabrik_t */ const bool is_no_close_factory() {return no_close_factory;} void set_no_close_factory(bool yesno) { no_close_factory = yesno;} + const factory_desc_t* get_pending_upgrade() const { return pending_upgrade; } /** * get and set shipment size diff --git a/simworld.cc b/simworld.cc index a379e10736..6058d66659 100644 --- a/simworld.cc +++ b/simworld.cc @@ -3935,8 +3935,37 @@ void karte_t::new_month() { if(fab_list.is_contained(fab)) { + const factory_desc_t* upgrade_desc = fab->get_pending_upgrade(); + const koord3d old_pos = fab->get_pos(); gebaeude_t* gb = lookup_kartenboden( fab->get_pos().get_2d() )->find(); + const uint8 old_rot = gb ? gb->get_tile()->get_layout() : 0; + + // Save connection lists before the factory is destroyed. + vector_tpl old_lieferziele( upgrade_desc ? fab->get_lieferziele() : vector_tpl() ); + vector_tpl old_suppliers( upgrade_desc ? fab->get_suppliers() : vector_tpl() ); + hausbauer_t::remove(get_public_player(), gb); + // fab pointer is invalid from here on. + + if( upgrade_desc ) { + fabrik_t* new_fab = factory_builder_t::build_factory(NULL, upgrade_desc, -1, old_rot, old_pos, get_public_player()); + if( new_fab ) { + // Re-link to former consumers: check if new factory produces what each consumer needs. + FOR(vector_tpl, consumer_pos, old_lieferziele) { + fabrik_t* consumer = fabrik_t::get_fab(consumer_pos); + if( consumer ) { + consumer->add_supplier(new_fab); + } + } + // Re-link to former suppliers: check if new factory needs what each supplier produces. + FOR(vector_tpl, supplier_pos, old_suppliers) { + fabrik_t* supplier = fabrik_t::get_fab(supplier_pos); + if( supplier ) { + new_fab->add_supplier(supplier); + } + } + } + } } } INT_CHECK("simworld 1278");