← Back to team overview

widelands-dev team mailing list archive

Re: [Merge] lp:~widelands-dev/widelands/constructionsite_options into lp:widelands

 

No problem. I have very little time for Widelands at the moment anyway :)

Diff comments:

> 
> === added file 'src/logic/map_objects/tribes/building_settings.cc'
> --- src/logic/map_objects/tribes/building_settings.cc	1970-01-01 00:00:00 +0000
> +++ src/logic/map_objects/tribes/building_settings.cc	2019-05-28 15:09:01 +0000
> @@ -0,0 +1,346 @@
> +/*
> + * Copyright (C) 2002-2019 by the Widelands Development Team
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
> + *
> + */
> +
> +#include "logic/map_objects/tribes/building_settings.h"
> +
> +#include "io/fileread.h"
> +#include "io/filewrite.h"
> +#include "logic/game.h"
> +#include "logic/game_data_error.h"
> +#include "logic/map_objects/tribes/militarysite.h"
> +#include "logic/map_objects/tribes/productionsite.h"
> +#include "logic/map_objects/tribes/trainingsite.h"
> +#include "logic/map_objects/tribes/tribe_descr.h"
> +#include "logic/map_objects/tribes/warehouse.h"
> +
> +namespace Widelands {
> +
> +ProductionsiteSettings::ProductionsiteSettings(const ProductionSiteDescr& descr)
> +		: BuildingSettings(descr.name()), stopped(false) {
> +	for (WareRange i(descr.input_wares()); i; ++i) {

Done

> +		ware_queues.push_back(std::make_pair(i.current->first,
> +				InputQueueSetting{i.current->second, i.current->second, kPriorityNormal}));
> +	}
> +	for (WareRange i(descr.input_workers()); i; ++i) {
> +		worker_queues.push_back(std::make_pair(i.current->first,
> +				InputQueueSetting{i.current->second, i.current->second, kPriorityNormal}));
> +	}
> +}
> +
> +MilitarysiteSettings::MilitarysiteSettings(const MilitarySiteDescr& descr)
> +		: BuildingSettings(descr.name()),
> +	  max_capacity(descr.get_max_number_of_soldiers()),
> +	  desired_capacity(descr.get_max_number_of_soldiers()),
> +	  prefer_heroes(descr.prefers_heroes_at_start_) {
> +}
> +
> +TrainingsiteSettings::TrainingsiteSettings(const TrainingSiteDescr& descr)
> +	: ProductionsiteSettings(descr),
> +	  max_capacity(descr.get_max_number_of_soldiers()),
> +	  desired_capacity(descr.get_max_number_of_soldiers()) {
> +}
> +
> +WarehouseSettings::WarehouseSettings(const WarehouseDescr& wh, const TribeDescr& tribe)
> +		: BuildingSettings(wh.name()), launch_expedition_allowed(wh.get_isport()), launch_expedition(false) {
> +	for (const DescriptionIndex di : tribe.wares()) {
> +		ware_preferences.emplace(di, StockPolicy::kNormal);
> +	}
> +	for (const DescriptionIndex di : tribe.workers()) {
> +		worker_preferences.emplace(di, StockPolicy::kNormal);

has_demand_check() returns true only for soldiers and 2nd carriers, but a warehouse allows stock policies for all workers except the ones listed in worker_types_without_cost()

> +	}
> +	for (const DescriptionIndex di : tribe.worker_types_without_cost()) {
> +		worker_preferences.erase(di);
> +	}
> +}
> +
> +void ProductionsiteSettings::apply(const BuildingSettings& bs) {
> +	BuildingSettings::apply(bs);
> +	if (upcast(const ProductionsiteSettings, s, &bs)) {
> +		stopped = s->stopped;
> +		for (auto& pair : ware_queues) {
> +			for (const auto& other : s->ware_queues) {
> +				if (pair.first == other.first) {
> +					pair.second.priority = other.second.priority;
> +					pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
> +					break;
> +				}
> +			}
> +		}
> +		for (auto& pair : worker_queues) {
> +			for (const auto& other : s->worker_queues) {
> +				if (pair.first == other.first) {
> +					pair.second.priority = other.second.priority;
> +					pair.second.desired_fill = std::min(pair.second.max_fill, other.second.desired_fill);
> +					break;
> +				}
> +			}
> +		}
> +	}
> +}
> +
> +void TrainingsiteSettings::apply(const BuildingSettings& bs) {
> +	ProductionsiteSettings::apply(bs);
> +	if (upcast(const TrainingsiteSettings, s, &bs)) {
> +		desired_capacity = std::min(max_capacity, s->desired_capacity);
> +	}
> +}
> +
> +void MilitarysiteSettings::apply(const BuildingSettings& bs) {
> +	BuildingSettings::apply(bs);
> +	if (upcast(const MilitarysiteSettings, s, &bs)) {
> +		desired_capacity = std::min(max_capacity, s->desired_capacity);
> +		prefer_heroes = s->prefer_heroes;
> +	}
> +}
> +
> +void WarehouseSettings::apply(const BuildingSettings& bs) {
> +	BuildingSettings::apply(bs);
> +	if (upcast(const WarehouseSettings, s, &bs)) {
> +		for (auto& pair : ware_preferences) {
> +			const auto it = s->ware_preferences.find(pair.first);
> +			if (it != s->ware_preferences.end()) {
> +				pair.second = it->second;
> +			}
> +		}
> +		for (auto& pair : worker_preferences) {
> +			const auto it = s->worker_preferences.find(pair.first);
> +			if (it != s->worker_preferences.end()) {
> +				pair.second = it->second;
> +			}
> +		}
> +		launch_expedition = launch_expedition_allowed && s->launch_expedition;
> +	}
> +}
> +
> +// Saveloading
> +
> +constexpr uint8_t kCurrentPacketVersion = 1;
> +constexpr uint8_t kCurrentPacketVersionMilitarysite = 1;
> +constexpr uint8_t kCurrentPacketVersionProductionsite = 1;
> +constexpr uint8_t kCurrentPacketVersionTrainingsite = 1;
> +constexpr uint8_t kCurrentPacketVersionWarehouse = 1;
> +
> +enum class BuildingType : uint8_t {
> +	kWarehouse = 1,
> +	kProductionsite = 2,
> +	kTrainingsite = 3,
> +	kMilitarysite = 4,
> +};
> +
> +// static
> +BuildingSettings* BuildingSettings::load(const Game& game, const TribeDescr& tribe, FileRead& fr) {
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersion) {
> +			const std::string name(fr.c_string());
> +			const DescriptionIndex index = game.tribes().building_index(name);
> +			const BuildingType type = static_cast<BuildingType>(fr.unsigned_8());
> +			BuildingSettings* result = nullptr;
> +			switch (type) {
> +				case BuildingType::kTrainingsite: {
> +					result = new TrainingsiteSettings(*dynamic_cast<const TrainingSiteDescr*>(
> +							game.tribes().get_building_descr(index)));
> +					break;
> +				}
> +				case BuildingType::kProductionsite: {
> +					result = new ProductionsiteSettings(*dynamic_cast<const ProductionSiteDescr*>(
> +							game.tribes().get_building_descr(index)));
> +					break;
> +				}
> +				case BuildingType::kMilitarysite: {
> +					result = new MilitarysiteSettings(*dynamic_cast<const MilitarySiteDescr*>(
> +							game.tribes().get_building_descr(index)));
> +					break;
> +				}
> +				case BuildingType::kWarehouse: {
> +					result = new WarehouseSettings(*dynamic_cast<const WarehouseDescr*>(
> +							game.tribes().get_building_descr(index)), tribe);
> +					break;
> +				}
> +			}
> +			if (!result) {
> +				throw wexception("Unknown building category %u (%s)", static_cast<uint8_t>(type), name.c_str());
> +			}
> +			result->read(game, fr);
> +			return result;
> +		} else {
> +			throw UnhandledVersionError(
> +			   "BuildingSettings_load", packet_version, kCurrentPacketVersion);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("BuildingSettings_load: %s", e.what());
> +	}
> +	NEVER_HERE();
> +}
> +
> +void BuildingSettings::read(const Game&, FileRead&) {
> +	// Header was peeled away by load()
> +}
> +
> +void BuildingSettings::save(const Game&, FileWrite& fw) const {
> +	fw.unsigned_8(kCurrentPacketVersion);
> +	fw.c_string(descr_.c_str());
> +}
> +
> +void MilitarysiteSettings::read(const Game& game, FileRead& fr) {
> +	BuildingSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionMilitarysite) {
> +			desired_capacity = fr.unsigned_32();
> +			prefer_heroes = fr.unsigned_8();
> +		} else {
> +			throw UnhandledVersionError(
> +			   "MilitarysiteSettings", packet_version, kCurrentPacketVersionMilitarysite);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("MilitarysiteSettings: %s", e.what());
> +	}
> +}
> +
> +void MilitarysiteSettings::save(const Game& game, FileWrite& fw) const {
> +	BuildingSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kMilitarysite));
> +	fw.unsigned_8(kCurrentPacketVersionMilitarysite);
> +
> +	fw.unsigned_32(desired_capacity);
> +	fw.unsigned_8(prefer_heroes ? 1 : 0);
> +}
> +
> +void ProductionsiteSettings::read(const Game& game, FileRead& fr) {
> +	BuildingSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionProductionsite) {
> +			stopped = fr.unsigned_8();
> +			const uint32_t nr_wares = fr.unsigned_32();
> +			const uint32_t nr_workers = fr.unsigned_32();
> +			for (uint32_t i = 0; i < nr_wares; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint32_t fill = fr.unsigned_32();
> +				const int32_t priority = fr.signed_32();
> +				ware_queues.at(i).first = di;
> +				ware_queues.at(i).second.desired_fill = fill;
> +				ware_queues.at(i).second.priority = priority;
> +			}
> +			for (uint32_t i = 0; i < nr_workers; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint32_t fill = fr.unsigned_32();
> +				const int32_t priority = fr.signed_32();
> +				worker_queues.at(i).first = di;
> +				worker_queues.at(i).second.desired_fill = fill;
> +				worker_queues.at(i).second.priority = priority;
> +			}
> +		} else {
> +			throw UnhandledVersionError(
> +			   "ProductionsiteSettings", packet_version, kCurrentPacketVersionProductionsite);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("ProductionsiteSettings: %s", e.what());
> +	}
> +}
> +
> +void ProductionsiteSettings::save(const Game& game, FileWrite& fw) const {
> +	BuildingSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kProductionsite));
> +	fw.unsigned_8(kCurrentPacketVersionProductionsite);
> +
> +	fw.unsigned_8(stopped ? 1 : 0);
> +	fw.unsigned_32(ware_queues.size());
> +	fw.unsigned_32(worker_queues.size());
> +	for (const auto& pair : ware_queues) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_32(pair.second.desired_fill);
> +		fw.signed_32(pair.second.priority);
> +	}
> +	for (const auto& pair : worker_queues) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_32(pair.second.desired_fill);
> +		fw.signed_32(pair.second.priority);
> +	}
> +}
> +
> +void TrainingsiteSettings::read(const Game& game, FileRead& fr) {
> +	ProductionsiteSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionTrainingsite) {
> +			desired_capacity = fr.unsigned_32();
> +		} else {
> +			throw UnhandledVersionError(
> +			   "TrainingsiteSettings", packet_version, kCurrentPacketVersionTrainingsite);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("TrainingsiteSettings: %s", e.what());
> +	}
> +}
> +
> +void TrainingsiteSettings::save(const Game& game, FileWrite& fw) const {
> +	ProductionsiteSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kTrainingsite));
> +	fw.unsigned_8(kCurrentPacketVersionTrainingsite);
> +	fw.unsigned_32(desired_capacity);
> +}
> +
> +void WarehouseSettings::read(const Game& game, FileRead& fr) {
> +	BuildingSettings::read(game, fr);
> +	try {
> +		const uint8_t packet_version = fr.unsigned_8();
> +		if (packet_version == kCurrentPacketVersionWarehouse) {
> +			launch_expedition = fr.unsigned_8();
> +			const uint32_t nr_wares = fr.unsigned_32();
> +			const uint32_t nr_workers = fr.unsigned_32();
> +			for (uint32_t i = 0; i < nr_wares; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint8_t pref = fr.unsigned_8();
> +				ware_preferences[di] = static_cast<StockPolicy>(pref);
> +			}
> +			for (uint32_t i = 0; i < nr_workers; ++i) {
> +				const DescriptionIndex di = fr.unsigned_32();
> +				const uint8_t pref = fr.unsigned_8();
> +				worker_preferences[di] = static_cast<StockPolicy>(pref);
> +			}
> +		} else {
> +			throw UnhandledVersionError(
> +			   "WarehouseSettings", packet_version, kCurrentPacketVersionWarehouse);
> +		}
> +	} catch (const WException& e) {
> +		throw GameDataError("WarehouseSettings: %s", e.what());
> +	}
> +}
> +
> +void WarehouseSettings::save(const Game& game, FileWrite& fw) const {
> +	BuildingSettings::save(game, fw);
> +	fw.unsigned_8(static_cast<uint8_t>(BuildingType::kWarehouse));
> +	fw.unsigned_8(kCurrentPacketVersionWarehouse);
> +
> +	fw.unsigned_8(launch_expedition ? 1 : 0);
> +	fw.unsigned_32(ware_preferences.size());
> +	fw.unsigned_32(worker_preferences.size());
> +	for (const auto& pair : ware_preferences) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_8(static_cast<uint8_t>(pair.second));
> +	}
> +	for (const auto& pair : worker_preferences) {
> +		fw.unsigned_32(pair.first);
> +		fw.unsigned_8(static_cast<uint8_t>(pair.second));
> +	}
> +}
> +
> +} // namespace Widelands
> 
> === modified file 'src/logic/map_objects/tribes/constructionsite.cc'
> --- src/logic/map_objects/tribes/constructionsite.cc	2019-05-26 17:21:15 +0000
> +++ src/logic/map_objects/tribes/constructionsite.cc	2019-05-28 15:09:01 +0000
> @@ -214,6 +321,138 @@
>  
>  /*
>  ===============
> +Start building the next enhancement even before the base building is completed.
> +===============
> +*/
> +void ConstructionSite::enhance(Game&) {
> +	assert(building_->enhancement() != INVALID_INDEX);
> +	Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::LOST));
> +
> +	info_.intermediates.push_back(building_);
> +	old_buildings_.push_back(owner().tribe().building_index(building_->name()));
> +	building_ = owner().tribe().get_building_descr(building_->enhancement());
> +	assert(building_);
> +	info_.becomes = building_;
> +
> +	const std::map<DescriptionIndex, uint8_t>& buildcost = building_->enhancement_cost();
> +	const size_t buildcost_size = buildcost.size();
> +	std::set<DescriptionIndex> new_ware_types;
> +	for (std::map<DescriptionIndex, uint8_t>::const_iterator it = buildcost.begin(); it != buildcost.end(); ++it) {
> +		bool found = false;
> +		for (const auto& queue : wares_) {
> +			if (queue->get_index() == it->first) {
> +				found = true;
> +				break;
> +			}
> +		}
> +		if (!found) {
> +			new_ware_types.insert(it->first);
> +		}
> +	}
> +
> +	const size_t old_size = wares_.size();
> +	wares_.resize(old_size + new_ware_types.size());
> +	std::map<DescriptionIndex, uint8_t>::const_iterator it = buildcost.begin();
> +
> +	size_t new_wares_index = 0;
> +	for (size_t i = 0; i < buildcost_size; ++i, ++it) {
> +		if (new_ware_types.count(it->first)) {
> +			WaresQueue& wq = *(wares_[old_size + new_wares_index] = new WaresQueue(*this, it->first, it->second));
> +			wq.set_callback(ConstructionSite::wares_queue_callback, this);
> +			wq.set_consume_interval(CONSTRUCTIONSITE_STEP_TIME);
> +			++new_wares_index;
> +		} else {
> +			assert(i >= new_wares_index);
> +			WaresQueue& wq = *wares_[i - new_wares_index];
> +			wq.set_max_size(wq.get_max_size() + it->second);
> +			wq.set_max_fill(wq.get_max_fill() + it->second);
> +		}
> +		work_steps_ += it->second;
> +	}
> +
> +	BuildingSettings* old_settings = settings_.release();
> +	if (upcast(const WarehouseDescr, wd, building_)) {
> +		WarehouseSettings* new_settings = new WarehouseSettings(*wd, owner().tribe());
> +		settings_.reset(new_settings);
> +		if (upcast(WarehouseSettings, ws, old_settings)) {
> +			for (const auto& pair : ws->ware_preferences) {
> +				new_settings->ware_preferences[pair.first] = pair.second;
> +			}
> +			for (const auto& pair : ws->worker_preferences) {
> +				new_settings->worker_preferences[pair.first] = pair.second;
> +			}
> +			new_settings->launch_expedition = ws->launch_expedition && building_->get_isport();
> +		}
> +	} else if (upcast(const TrainingSiteDescr, td, building_)) {
> +		TrainingsiteSettings* new_settings = new TrainingsiteSettings(*td);
> +		settings_.reset(new_settings);
> +		if (upcast(ProductionsiteSettings, ps, old_settings)) {
> +			new_settings->stopped = ps->stopped;
> +			for (const auto& pair_old : ps->ware_queues) {
> +				for (auto& pair_new : new_settings->ware_queues) {

If they exist, I think yes, but some wares may be contained in the old but not the new settings and vice versa. So to get rid of the loops, we would need something like
size_t j = 0;
for (size_t i = 0; i < ps->ware_queues.size(); ++i) {
  if (ps->ware_queues[i].first == new_settings->ware_queues[j].first) {
    // Copy settings
    ++j;
  }
}
But this looks like it would be too easy to accidentally skip something without noticing. Also, I believe (but am not sure) that modders could reorder the indices if they wanted to, so it would be fragile IMHO.

> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +			for (const auto& pair_old : ps->worker_queues) {
> +				for (auto& pair_new : new_settings->worker_queues) {
> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +			if (upcast(TrainingsiteSettings, ts, old_settings)) {
> +				new_settings->desired_capacity = std::min(new_settings->max_capacity, ts->desired_capacity);
> +			}
> +		}
> +	} else if (upcast(const ProductionSiteDescr, pd, building_)) {
> +		ProductionsiteSettings* new_settings = new ProductionsiteSettings(*pd);
> +		settings_.reset(new_settings);
> +		if (upcast(ProductionsiteSettings, ps, old_settings)) {
> +			new_settings->stopped = ps->stopped;
> +			for (const auto& pair_old : ps->ware_queues) {
> +				for (auto& pair_new : new_settings->ware_queues) {
> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +			for (const auto& pair_old : ps->worker_queues) {
> +				for (auto& pair_new : new_settings->worker_queues) {
> +					if (pair_new.first == pair_old.first) {
> +						pair_new.second.priority = pair_old.second.priority;
> +						pair_new.second.desired_fill = std::min(pair_old.second.desired_fill, pair_new.second.max_fill);
> +						break;
> +					}
> +				}
> +			}
> +		}
> +	} else if (upcast(const MilitarySiteDescr, md, building_)) {
> +		MilitarysiteSettings* new_settings = new MilitarysiteSettings(*md);
> +		settings_.reset(new_settings);
> +		if (upcast(MilitarysiteSettings, ms, old_settings)) {
> +			new_settings->desired_capacity = std::max<uint32_t>(1, std::min<uint32_t>(
> +					new_settings->max_capacity, ms->desired_capacity));
> +			new_settings->prefer_heroes = ms->prefer_heroes;
> +		}
> +	} else {
> +		// TODO(Nordfriese): Add support for markets when trading is implemented
> +		log("WARNING: Enhanced constructionsite to a %s, which is not of any known building type\n",
> +				building_->name().c_str());
> +	}
> +	Notifications::publish(NoteImmovable(this, NoteImmovable::Ownership::GAINED));
> +	Notifications::publish(NoteBuilding(serial(), NoteBuilding::Action::kChanged));
> +}
> +
> +/*
> +===============
>  Construction sites only burn if some of the work has been completed.
>  ===============
>  */
> 
> === modified file 'src/logic/map_objects/tribes/militarysite.cc'
> --- src/logic/map_objects/tribes/militarysite.cc	2019-05-26 17:21:15 +0000
> +++ src/logic/map_objects/tribes/militarysite.cc	2019-05-28 15:09:01 +0000
> @@ -982,6 +982,13 @@
>  	return false;
>  }
>  
> +const BuildingSettings* MilitarySite::create_building_settings() const {
> +	MilitarysiteSettings* settings = new MilitarysiteSettings(descr());
> +	settings->desired_capacity = std::min(settings->max_capacity, soldier_control_.soldier_capacity());
> +	settings->prefer_heroes = soldier_preference_ == SoldierPreference::kHeroes;

Either you overlooked the ==, or I don´t get what you mean here…

> +	return settings;
> +}
> +
>  // setters
>  
>  void MilitarySite::set_soldier_preference(SoldierPreference p) {


-- 
https://code.launchpad.net/~widelands-dev/widelands/constructionsite_options/+merge/367428
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/constructionsite_options.


References