Przeglądaj źródła

Team alignments implemented

nordsoft 2 lat temu
rodzic
commit
b1f2c7aed4

+ 61 - 1
client/gui/InterfaceObjectConfigurable.cpp

@@ -55,7 +55,6 @@ void InterfaceObjectConfigurable::init(const JsonNode &config)
 						: item["name"].String();
 		widgets[name] = buildWidget(item);
 	}
-	variables = config["variables"];
 }
 
 const JsonNode & InterfaceObjectConfigurable::variable(const std::string & name) const
@@ -94,6 +93,16 @@ Point InterfaceObjectConfigurable::readPosition(const JsonNode & config) const
 	return p;
 }
 
+Rect InterfaceObjectConfigurable::readRect(const JsonNode & config) const
+{
+	Rect p;
+	p.x = config["x"].Integer();
+	p.y = config["y"].Integer();
+	p.w = config["w"].Integer();
+	p.h = config["h"].Integer();
+	return p;
+}
+
 ETextAlignment InterfaceObjectConfigurable::readTextAlignment(const JsonNode & config) const
 {
 	if(!config.isNull())
@@ -275,6 +284,45 @@ std::shared_ptr<CSlider> InterfaceObjectConfigurable::buildSlider(const JsonNode
 	return std::make_shared<CSlider>(position, length, callbacks.at(config["callback"].String()), itemsVisible, itemsTotal, value, horizontal, style);
 }
 
+std::shared_ptr<CAnimImage> InterfaceObjectConfigurable::buildImage(const JsonNode & config) const
+{
+	auto position = readPosition(config["position"]);
+	auto image = config["image"].String();
+	int group = config["group"].isNull() ? 0 : config["group"].Integer();
+	int frame = config["frame"].isNull() ? 0 : config["frame"].Integer();
+	return std::make_shared<CAnimImage>(image, frame, group, position.x, position.y);
+}
+
+std::shared_ptr<CFilledTexture> InterfaceObjectConfigurable::buildTexture(const JsonNode & config) const
+{
+	auto image = config["image"].String();
+	auto rect = readRect(config);
+	return std::make_shared<CFilledTexture>(image, rect);
+}
+
+std::shared_ptr<CShowableAnim> InterfaceObjectConfigurable::buildAnimation(const JsonNode & config) const
+{
+	auto position = readPosition(config["position"]);
+	auto image = config["image"].String();
+	ui8 flags = 0;
+	if(!config["repeat"].Bool())
+		flags |= CShowableAnim::EFlags::PLAY_ONCE;
+	
+	int group = config["group"].isNull() ? 0 : config["group"].Integer();
+	auto anim = std::make_shared<CShowableAnim>(position.x, position.y, image, flags, 4, group);
+	if(!config["alpha"].isNull())
+		anim->setAlpha(config["alpha"].Integer());
+	if(!config["callback"].isNull())
+		anim->callback = std::bind(callbacks.at(config["callback"].String()), 0);
+	if(!config["frames"].isNull())
+	{
+		auto b = config["frames"]["start"].Integer();
+		auto e = config["frames"]["end"].Integer();
+		anim->set(group, b, e);
+	}
+	return anim;
+}
+
 std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildWidget(const JsonNode & config) const
 {
 	assert(!config.isNull());
@@ -283,6 +331,18 @@ std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildWidget(const JsonN
 	{
 		return buildPicture(config);
 	}
+	if(type == "image")
+	{
+		return buildImage(config);
+	}
+	if(type == "texture")
+	{
+		return buildTexture(config);
+	}
+	if(type == "animation")
+	{
+		return buildAnimation(config);
+	}
 	if(type == "label")
 	{
 		return buildLabel(config);

+ 8 - 0
client/gui/InterfaceObjectConfigurable.h

@@ -21,6 +21,9 @@ class CToggleButton;
 class CButton;
 class CLabelGroup;
 class CSlider;
+class CAnimImage;
+class CShowableAnim;
+class CFilledTexture;
 
 class InterfaceObjectConfigurable: public CIntObject
 {
@@ -47,6 +50,7 @@ protected:
 	
 	//basic serializers
 	Point readPosition(const JsonNode &) const;
+	Rect readRect(const JsonNode &) const;
 	ETextAlignment readTextAlignment(const JsonNode &) const;
 	SDL_Color readColor(const JsonNode &) const;
 	EFonts readFont(const JsonNode &) const;
@@ -61,6 +65,10 @@ protected:
 	std::shared_ptr<CButton> buildButton(const JsonNode &) const;
 	std::shared_ptr<CLabelGroup> buildLabelGroup(const JsonNode &) const;
 	std::shared_ptr<CSlider> buildSlider(const JsonNode &) const;
+	std::shared_ptr<CAnimImage> buildImage(const JsonNode &) const;
+	std::shared_ptr<CShowableAnim> buildAnimation(const JsonNode &) const;
+	std::shared_ptr<CFilledTexture> buildTexture(const JsonNode &) const;
+	
 	
 	//composite widgets
 	virtual std::shared_ptr<CIntObject> buildCustomWidget(const JsonNode & config);

+ 74 - 5
client/lobby/RandomMapTab.cpp

@@ -155,6 +155,7 @@ void RandomMapTab::updateMapInfoByHost()
 
 	mapInfo->mapHeader->howManyTeams = playersToGen;
 
+	std::set<TeamID> occupiedTeams;
 	for(int i = 0; i < playersToGen; ++i)
 	{
 		PlayerInfo player;
@@ -168,11 +169,25 @@ void RandomMapTab::updateMapInfoByHost()
 		{
 			player.canHumanPlay = true;
 		}
-		player.team = TeamID(i);
+		auto team = mapGenOptions->getPlayersSettings().at(PlayerColor(i)).getTeam();
+		player.team = team;
+		occupiedTeams.insert(team);
 		player.hasMainTown = true;
 		player.generateHeroAtMainTown = true;
 		mapInfo->mapHeader->players.push_back(player);
 	}
+	for(auto & player : mapInfo->mapHeader->players)
+	{
+		for(int i = 0; player.team == TeamID::NO_TEAM; ++i)
+		{
+			TeamID team(i);
+			if(!occupiedTeams.count(team))
+			{
+				player.team = team;
+				occupiedTeams.insert(team);
+			}
+		}
+	}
 
 	mapInfoChanged(mapInfo, mapGenOptions);
 }
@@ -456,13 +471,67 @@ TeamAlignmentsWidget::TeamAlignmentsWidget(RandomMapTab & randomMapTab):
 {
 	OBJ_CONSTRUCTION;
 	
-	pos.w = 300;
-	pos.h = 300;
+	int humanPlayers = randomMapTab.obtainMapGenOptions().getPlayerCount();
+	int cpuPlayers = randomMapTab.obtainMapGenOptions().getCompOnlyPlayerCount();
+	int totalPlayers = humanPlayers == CMapGenOptions::RANDOM_SIZE || cpuPlayers == CMapGenOptions::RANDOM_SIZE
+	? PlayerColor::PLAYER_LIMIT_I : humanPlayers + cpuPlayers;
+	assert(totalPlayers <= PlayerColor::PLAYER_LIMIT_I);
+	auto settings = randomMapTab.obtainMapGenOptions().getPlayersSettings();
+	
+	pos.w = 80 + totalPlayers * 32;
+	pos.h = 80 + totalPlayers * 32;
 	background = std::make_shared<CFilledTexture>("Bl3DCvex", pos);
 	center(pos);
 	
-	buttonOk = std::make_shared<CButton>(Point(43, 240), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], [](){});
-	buttonCancel = std::make_shared<CButton>(Point(193, 240), "MUBCANC.DEF", CGI->generaltexth->zelp[561], [&]()
+	for(int plId = 0; plId < totalPlayers; ++plId)
+	{
+		players.push_back(std::make_shared<CToggleGroup>([&, totalPlayers, plId](int sel)
+		{
+			SObjectConstruction obj__i(players[plId].get());
+			for(int teamId = 0; teamId < totalPlayers; ++teamId)
+			{
+				auto button = std::dynamic_pointer_cast<CToggleButton>(players[plId]->buttons[teamId]);
+				assert(button);
+				if(sel == teamId)
+				{
+					button->addOverlay(std::make_shared<CAnimImage>("ITGFLAGS", plId, 0, 8, 8));
+				}
+				else
+				{
+					button->addOverlay(std::make_shared<CPicture>("TeamPlSl"));
+				}
+			}
+		}));
+		
+		SObjectConstruction obj__i(players.back().get());
+		for(int teamId = 0; teamId < totalPlayers; ++teamId)
+		{
+			Point p(40 + plId * 32, 20 + teamId * 32);
+			placeholders.push_back(std::make_shared<CPicture>("TeamPlSl", p.x, p.y));
+			auto button = std::make_shared<CToggleButton>(p, "TeamPlSl", std::pair<std::string, std::string>{"", ""});
+			button->pos.w = 32;
+			button->pos.h = 32;
+			players.back()->addToggle(teamId, button);
+		}
+		
+		auto team = settings.at(PlayerColor(plId)).getTeam();
+		if(team == TeamID::NO_TEAM)
+			players.back()->setSelected(plId);
+		else
+			players.back()->setSelected(team.getNum());
+	}
+	
+	buttonOk = std::make_shared<CButton>(Point(40, 40 + totalPlayers * 32), "MUBCHCK.DEF", CGI->generaltexth->zelp[560], [&]()
+	{
+		for(int plId = 0; plId < players.size(); ++plId)
+		{
+			randomMapTab.obtainMapGenOptions().setPlayerTeam(PlayerColor(plId), TeamID(players[plId]->getSelected()));
+		}
+		randomMapTab.updateMapInfoByHost();
+		assert(GH.topInt().get() == this);
+		GH.popInt(GH.topInt());
+	});
+	buttonCancel = std::make_shared<CButton>(Point(120, 40 + totalPlayers * 32), "MUBCANC.DEF", CGI->generaltexth->zelp[561], [&]()
 	{
 		assert(GH.topInt().get() == this);
 		GH.popInt(GH.topInt());

+ 4 - 1
client/lobby/RandomMapTab.h

@@ -26,6 +26,7 @@ class CToggleButton;
 class CLabel;
 class CLabelGroup;
 class CSlider;
+class CPicture;
 
 class RandomMapTab : public InterfaceObjectConfigurable
 {
@@ -35,6 +36,7 @@ public:
 	void updateMapInfoByHost();
 	void setMapGenOptions(std::shared_ptr<CMapGenOptions> opts);
 	void setTemplate(const CRmgTemplate *);
+	CMapGenOptions & obtainMapGenOptions() {return *mapGenOptions;}
 
 	CFunctionList<void(std::shared_ptr<CMapInfo>, std::shared_ptr<CMapGenOptions>)> mapInfoChanged;
 
@@ -97,5 +99,6 @@ private:
 	std::shared_ptr<CFilledTexture> background;
 	std::shared_ptr<CLabelGroup> labels;
 	std::shared_ptr<CButton> buttonOk, buttonCancel;
-	std::vector<std::shared_ptr<CToggleGroup>> teams;
+	std::vector<std::shared_ptr<CToggleGroup>> players;
+	std::vector<std::shared_ptr<CPicture>> placeholders;
 };

+ 5 - 0
client/widgets/Buttons.cpp

@@ -449,6 +449,11 @@ void CToggleGroup::selectionChanged(int to)
 		parent->redraw();
 }
 
+int CToggleGroup::getSelected() const
+{
+	return selectedID;
+}
+
 CVolumeSlider::CVolumeSlider(const Point & position, const std::string & defName, const int value, const std::pair<std::string, std::string> * const help)
 	: CIntObject(LCLICK | RCLICK | WHEEL),
 	value(value),

+ 1 - 0
client/widgets/Buttons.h

@@ -185,6 +185,7 @@ public:
 	/// in some cases, e.g. LoadGame difficulty selection, after refreshing the UI, the ToggleGroup should 
 	/// reset all of it's child buttons to BLOCK state, then make selection again
 	void setSelectedOnly(int id);
+	int getSelected() const;
 };
 
 /// A typical slider for volume with an animated indicator

+ 1 - 1
client/widgets/Images.h

@@ -56,7 +56,7 @@ public:
 };
 
 /// area filled with specific texture
-class CFilledTexture : CIntObject
+class CFilledTexture : public CIntObject
 {
 	SDL_Surface * texture;
 

+ 1 - 4
config/translate.json

@@ -121,10 +121,7 @@
 			"defaultTemplate": "default",
 			"templateLabel": "Template",
 			"teamAlignmentsButton": "Setup...",
-			"teamAlignmentsLabel": "Team alignments",
-			"dirtRoad": "Dirt",
-			"gravelRoad": "Gravel",
-			"cobblestoneRoad": "Stone"
+			"teamAlignmentsLabel": "Team alignments"
 		}
 	}
 }

+ 3 - 0
lib/rmg/CMapGenOptions.cpp

@@ -136,12 +136,14 @@ void CMapGenOptions::resetPlayersMap()
 {
 
 	std::map<PlayerColor, TFaction> rememberTownTypes;
+	std::map<PlayerColor, TeamID> rememberTeam;
 
 	for (auto p : players)
 	{
 		auto town = p.second.getStartingTown();
 		if (town != RANDOM_SIZE)
 			rememberTownTypes[p.first] = town;
+		rememberTeam[p.first] = p.second.getTeam();
 	}
 
 
@@ -169,6 +171,7 @@ void CMapGenOptions::resetPlayersMap()
 			playerType = EPlayerType::COMP_ONLY;
 		}
 		player.setPlayerType(playerType);
+		player.setTeam(rememberTeam[pc]);
 		players[pc] = player;
 
 		if (vstd::contains(rememberTownTypes, pc))

+ 3 - 2
lib/rmg/CMapGenerator.cpp

@@ -188,6 +188,7 @@ void CMapGenerator::addPlayerInfo()
 
 	enum ETeams {CPHUMAN = 0, CPUONLY = 1, AFTER_LAST = 2};
 	std::array<std::list<int>, 2> teamNumbers;
+	std::set<int> teamsTotal;
 
 	int teamOffset = 0;
 	int playerCount = 0;
@@ -258,11 +259,11 @@ void CMapGenerator::addPlayerInfo()
 			player.team = TeamID(*itTeam);
 			teamNumbers[j].erase(itTeam);
 		}
+		teamsTotal.insert(player.team.getNum());
 		map->map().players[pSettings.getColor().getNum()] = player;
 	}
 
-	map->map().howManyTeams = (mapGenOptions.getTeamCount() == 0 ? mapGenOptions.getPlayerCount() : mapGenOptions.getTeamCount())
-			+ (mapGenOptions.getCompOnlyTeamCount() == 0 ? mapGenOptions.getCompOnlyPlayerCount() : mapGenOptions.getCompOnlyTeamCount());
+	map->map().howManyTeams = teamsTotal.size();
 }
 
 void CMapGenerator::genZones()