1 /*
2  * Copyright (C) 2002-2020 by the Widelands Development Team
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19 
20 #include "map_io/map_allowed_building_types_packet.h"
21 
22 #include "base/macros.h"
23 #include "io/profile.h"
24 #include "logic/game.h"
25 #include "logic/game_data_error.h"
26 #include "logic/map_objects/tribes/tribe_descr.h"
27 #include "logic/player.h"
28 
29 namespace Widelands {
30 
31 constexpr int32_t kCurrentPacketVersion = 1;
32 
read(FileSystem & fs,EditorGameBase & egbase,bool const skip,MapObjectLoader &)33 void MapAllowedBuildingTypesPacket::read(FileSystem& fs,
34                                          EditorGameBase& egbase,
35                                          bool const skip,
36                                          MapObjectLoader&) {
37 	if (skip) {
38 		return;
39 	}
40 
41 	Profile prof;
42 	try {
43 		prof.read("allowed_building_types", nullptr, fs);
44 	} catch (const WException&) {
45 		try {
46 			prof.read("allowed_buildings", nullptr, fs);
47 		} catch (...) {
48 			return;
49 		}
50 	} catch (...) {
51 		return;
52 	}
53 	try {
54 		int32_t const packet_version = prof.get_safe_section("global").get_safe_int("packet_version");
55 		if (packet_version == kCurrentPacketVersion) {
56 			PlayerNumber const nr_players = egbase.map().get_nrplayers();
57 			upcast(Game const, game, &egbase);
58 
59 			//  Now read all players and buildings.
60 			iterate_players_existing(p, nr_players, egbase, player) {
61 
62 				const TribeDescr& tribe = player->tribe();
63 				//  All building types default to false in the game (not in the
64 				//  editor).
65 				if (game) {
66 					for (DescriptionIndex i = 0; i < game->tribes().nrbuildings(); ++i) {
67 						player->allow_building_type(i, false);
68 					}
69 				}
70 				try {
71 					Section& s = prof.get_safe_section(
72 					   (boost::format("player_%u") % static_cast<unsigned int>(p)).str());
73 
74 					bool allowed;
75 					while (const char* const name = s.get_next_bool(nullptr, &allowed)) {
76 						const DescriptionIndex index = tribe.building_index(name);
77 						if (tribe.has_building(index)) {
78 							player->allow_building_type(index, allowed);
79 						} else {
80 							log("WARNING: MapAllowedBuildingTypesPacket - tribe %s does not define "
81 							    "building type \"%s\"\n",
82 							    tribe.name().c_str(), name);
83 						}
84 					}
85 				} catch (const WException& e) {
86 					throw GameDataError("player %u (%s): %s", p, tribe.name().c_str(), e.what());
87 				}
88 			}
89 		} else {
90 			throw UnhandledVersionError(
91 			   "MapAllowedBuildingTypesPacket", packet_version, kCurrentPacketVersion);
92 		}
93 	} catch (const WException& e) {
94 		throw GameDataError("allowed buildings: %s", e.what());
95 	}
96 }
97 
write(FileSystem & fs,EditorGameBase & egbase,MapObjectSaver &)98 void MapAllowedBuildingTypesPacket::write(FileSystem& fs, EditorGameBase& egbase, MapObjectSaver&) {
99 	Profile prof;
100 	prof.create_section("global").set_int("packet_version", kCurrentPacketVersion);
101 
102 	PlayerNumber const nr_players = egbase.map().get_nrplayers();
103 	iterate_players_existing_const(p, nr_players, egbase, player) {
104 		const TribeDescr& tribe = player->tribe();
105 		const std::string section_key =
106 		   (boost::format("player_%u") % static_cast<unsigned int>(p)).str();
107 		Section& section = prof.create_section(section_key.c_str());
108 
109 		//  Write for all buildings if it is enabled.
110 		for (const Widelands::DescriptionIndex& building_index : tribe.buildings()) {
111 			if (player->is_building_type_allowed(building_index)) {
112 				const BuildingDescr* building_descr =
113 				   egbase.tribes().get_building_descr(building_index);
114 				section.set_bool(building_descr->name().c_str(), true);
115 			}
116 		}
117 	}
118 
119 	prof.write("allowed_building_types", false, fs);
120 }
121 }  // namespace Widelands
122