mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-04 23:17:41 +02:00
Merge pull request #5422 from IvanSavenko/disposed_heroes_fix
[1.7] Do not allow heroes banned for player as starting heroes
This commit is contained in:
commit
b2642bb7d7
@ -432,6 +432,12 @@ OptionsTab::SelectionWindow::SelectionWindow(const PlayerColor & color, SelType
|
|||||||
unusableHeroes.insert(player.second.hero);
|
unusableHeroes.insert(player.second.hero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto & disposedHero : SEL->getMapInfo()->mapHeader->disposedHeroes)
|
||||||
|
{
|
||||||
|
if (!disposedHero.players.count(color))
|
||||||
|
allowedHeroes.erase(disposedHero.heroId);
|
||||||
|
}
|
||||||
|
|
||||||
allowedBonus.push_back(PlayerStartingBonus::RANDOM);
|
allowedBonus.push_back(PlayerStartingBonus::RANDOM);
|
||||||
|
|
||||||
if(initialHero != HeroTypeID::NONE|| SEL->getPlayerInfo(color).heroesNames.size() > 0)
|
if(initialHero != HeroTypeID::NONE|| SEL->getPlayerInfo(color).heroesNames.size() > 0)
|
||||||
@ -459,8 +465,10 @@ std::tuple<int, int> OptionsTab::SelectionWindow::calcLines(FactionID faction)
|
|||||||
for(auto & elemh : allowedHeroes)
|
for(auto & elemh : allowedHeroes)
|
||||||
{
|
{
|
||||||
const CHero * type = elemh.toHeroType();
|
const CHero * type = elemh.toHeroType();
|
||||||
if(type->heroClass->faction == faction)
|
if(type->heroClass->faction != faction)
|
||||||
count++;
|
continue;
|
||||||
|
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_tuple(
|
return std::make_tuple(
|
||||||
|
@ -39,11 +39,6 @@ void Rumor::serializeJson(JsonSerializeFormat & handler)
|
|||||||
handler.serializeStruct("text", text);
|
handler.serializeStruct("text", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
DisposedHero::DisposedHero() : heroId(0), portrait(255)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CMapEvent::CMapEvent()
|
CMapEvent::CMapEvent()
|
||||||
: humanAffected(false)
|
: humanAffected(false)
|
||||||
, computerAffected(false)
|
, computerAffected(false)
|
||||||
|
@ -56,26 +56,6 @@ struct DLL_LINKAGE Rumor
|
|||||||
void serializeJson(JsonSerializeFormat & handler);
|
void serializeJson(JsonSerializeFormat & handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The disposed hero struct describes which hero can be hired from which player.
|
|
||||||
struct DLL_LINKAGE DisposedHero
|
|
||||||
{
|
|
||||||
DisposedHero();
|
|
||||||
|
|
||||||
HeroTypeID heroId;
|
|
||||||
HeroTypeID portrait; /// The portrait id of the hero, -1 is default.
|
|
||||||
std::string name;
|
|
||||||
std::set<PlayerColor> players; /// Who can hire this hero (bitfield).
|
|
||||||
|
|
||||||
template <typename Handler>
|
|
||||||
void serialize(Handler & h)
|
|
||||||
{
|
|
||||||
h & heroId;
|
|
||||||
h & portrait;
|
|
||||||
h & name;
|
|
||||||
h & players;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// The map contains the map header, the tiles of the terrain, objects, heroes, towns, rumors...
|
/// The map contains the map header, the tiles of the terrain, objects, heroes, towns, rumors...
|
||||||
class DLL_LINKAGE CMap : public CMapHeader, public GameCallbackHolder
|
class DLL_LINKAGE CMap : public CMapHeader, public GameCallbackHolder
|
||||||
{
|
{
|
||||||
@ -138,7 +118,6 @@ public:
|
|||||||
void reindexObjects();
|
void reindexObjects();
|
||||||
|
|
||||||
std::vector<Rumor> rumors;
|
std::vector<Rumor> rumors;
|
||||||
std::vector<DisposedHero> disposedHeroes;
|
|
||||||
std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
|
std::vector<ConstTransitivePtr<CGHeroInstance> > predefinedHeroes;
|
||||||
std::set<SpellID> allowedSpells;
|
std::set<SpellID> allowedSpells;
|
||||||
std::set<ArtifactID> allowedArtifact;
|
std::set<ArtifactID> allowedArtifact;
|
||||||
|
@ -202,6 +202,24 @@ enum class EMapDifficulty : uint8_t
|
|||||||
IMPOSSIBLE = 4
|
IMPOSSIBLE = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The disposed hero struct describes which hero can be hired from which player.
|
||||||
|
struct DLL_LINKAGE DisposedHero
|
||||||
|
{
|
||||||
|
HeroTypeID heroId;
|
||||||
|
HeroTypeID portrait; /// The portrait id of the hero, -1 is default.
|
||||||
|
std::string name;
|
||||||
|
std::set<PlayerColor> players; /// Who can hire this hero (bitfield).
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
void serialize(Handler & h)
|
||||||
|
{
|
||||||
|
h & heroId;
|
||||||
|
h & portrait;
|
||||||
|
h & name;
|
||||||
|
h & players;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// The map header holds information about loss/victory condition,map format, version, players, height, width,...
|
/// The map header holds information about loss/victory condition,map format, version, players, height, width,...
|
||||||
class DLL_LINKAGE CMapHeader: public Serializeable
|
class DLL_LINKAGE CMapHeader: public Serializeable
|
||||||
{
|
{
|
||||||
@ -248,6 +266,8 @@ public:
|
|||||||
std::set<HeroTypeID> allowedHeroes;
|
std::set<HeroTypeID> allowedHeroes;
|
||||||
std::set<HeroTypeID> reservedCampaignHeroes; /// Heroes that have placeholders in this map and are reserved for campaign
|
std::set<HeroTypeID> reservedCampaignHeroes; /// Heroes that have placeholders in this map and are reserved for campaign
|
||||||
|
|
||||||
|
std::vector<DisposedHero> disposedHeroes;
|
||||||
|
|
||||||
bool areAnyPlayers; /// Unused. True if there are any playable players on the map.
|
bool areAnyPlayers; /// Unused. True if there are any playable players on the map.
|
||||||
|
|
||||||
/// "main quests" of the map that describe victory and loss conditions
|
/// "main quests" of the map that describe victory and loss conditions
|
||||||
@ -298,6 +318,8 @@ public:
|
|||||||
h & victoryIconIndex;
|
h & victoryIconIndex;
|
||||||
h & defeatMessage;
|
h & defeatMessage;
|
||||||
h & defeatIconIndex;
|
h & defeatIconIndex;
|
||||||
|
if (h.version >= Handler::Version::MAP_HEADER_DISPOSED_HEROES)
|
||||||
|
h & disposedHeroes;
|
||||||
h & translations;
|
h & translations;
|
||||||
if(!h.saving)
|
if(!h.saving)
|
||||||
registerMapStrings();
|
registerMapStrings();
|
||||||
|
@ -95,7 +95,6 @@ void CMapLoaderH3M::init()
|
|||||||
inputStream->seek(0);
|
inputStream->seek(0);
|
||||||
|
|
||||||
readHeader();
|
readHeader();
|
||||||
readDisposedHeroes();
|
|
||||||
readMapOptions();
|
readMapOptions();
|
||||||
readAllowedArtifacts();
|
readAllowedArtifacts();
|
||||||
readAllowedSpellsAbilities();
|
readAllowedSpellsAbilities();
|
||||||
@ -248,6 +247,7 @@ void CMapLoaderH3M::readHeader()
|
|||||||
readVictoryLossConditions();
|
readVictoryLossConditions();
|
||||||
readTeamInfo();
|
readTeamInfo();
|
||||||
readAllowedHeroes();
|
readAllowedHeroes();
|
||||||
|
readDisposedHeroes();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapLoaderH3M::readPlayerInfo()
|
void CMapLoaderH3M::readPlayerInfo()
|
||||||
@ -728,13 +728,13 @@ void CMapLoaderH3M::readDisposedHeroes()
|
|||||||
if(features.levelSOD)
|
if(features.levelSOD)
|
||||||
{
|
{
|
||||||
size_t disp = reader->readUInt8();
|
size_t disp = reader->readUInt8();
|
||||||
map->disposedHeroes.resize(disp);
|
mapHeader->disposedHeroes.resize(disp);
|
||||||
for(size_t g = 0; g < disp; ++g)
|
for(size_t g = 0; g < disp; ++g)
|
||||||
{
|
{
|
||||||
map->disposedHeroes[g].heroId = reader->readHero();
|
mapHeader->disposedHeroes[g].heroId = reader->readHero();
|
||||||
map->disposedHeroes[g].portrait = reader->readHeroPortrait();
|
mapHeader->disposedHeroes[g].portrait = reader->readHeroPortrait();
|
||||||
map->disposedHeroes[g].name = readLocalizedString(TextIdentifier("header", "heroes", map->disposedHeroes[g].heroId.getNum()));
|
mapHeader->disposedHeroes[g].name = readLocalizedString(TextIdentifier("header", "heroes", mapHeader->disposedHeroes[g].heroId.getNum()));
|
||||||
reader->readBitmaskPlayers(map->disposedHeroes[g].players, false);
|
reader->readBitmaskPlayers(mapHeader->disposedHeroes[g].players, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -640,19 +640,19 @@ void CMapFormatJson::readDisposedHeroes(JsonSerializeFormat & handler)
|
|||||||
hero.players = mask;
|
hero.players = mask;
|
||||||
//name and portrait are not used
|
//name and portrait are not used
|
||||||
|
|
||||||
map->disposedHeroes.push_back(hero);
|
mapHeader->disposedHeroes.push_back(hero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMapFormatJson::writeDisposedHeroes(JsonSerializeFormat & handler)
|
void CMapFormatJson::writeDisposedHeroes(JsonSerializeFormat & handler)
|
||||||
{
|
{
|
||||||
if(map->disposedHeroes.empty())
|
if(mapHeader->disposedHeroes.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto definitions = handler.enterStruct("predefinedHeroes");//DisposedHeroes are part of predefinedHeroes in VCMI map format
|
auto definitions = handler.enterStruct("predefinedHeroes");//DisposedHeroes are part of predefinedHeroes in VCMI map format
|
||||||
|
|
||||||
for(DisposedHero & hero : map->disposedHeroes)
|
for(DisposedHero & hero : mapHeader->disposedHeroes)
|
||||||
{
|
{
|
||||||
std::string type = HeroTypeID::encode(hero.heroId.getNum());
|
std::string type = HeroTypeID::encode(hero.heroId.getNum());
|
||||||
|
|
||||||
|
@ -70,6 +70,10 @@ enum class ESerializationVersion : int32_t
|
|||||||
REWARDABLE_GUARDS, // 871 - fix missing serialization of guards in rewardable objects
|
REWARDABLE_GUARDS, // 871 - fix missing serialization of guards in rewardable objects
|
||||||
MARKET_TRANSLATION_FIX, // 872 - remove serialization of markets translateable strings
|
MARKET_TRANSLATION_FIX, // 872 - remove serialization of markets translateable strings
|
||||||
EVENT_OBJECTS_DELETION, //873 - allow events to remove map objects
|
EVENT_OBJECTS_DELETION, //873 - allow events to remove map objects
|
||||||
|
|
||||||
|
RELEASE_160 = 873,
|
||||||
|
|
||||||
|
MAP_HEADER_DISPOSED_HEROES, // map header contains disposed heroes list
|
||||||
|
|
||||||
CURRENT = EVENT_OBJECTS_DELETION
|
CURRENT = MAP_HEADER_DISPOSED_HEROES
|
||||||
};
|
};
|
||||||
|
@ -974,10 +974,26 @@ void CVCMIServer::optionSetBonus(PlayerColor player, PlayerStartingBonus id)
|
|||||||
|
|
||||||
bool CVCMIServer::canUseThisHero(PlayerColor player, HeroTypeID ID)
|
bool CVCMIServer::canUseThisHero(PlayerColor player, HeroTypeID ID)
|
||||||
{
|
{
|
||||||
return VLC->heroh->size() > ID
|
if (!ID.hasValue())
|
||||||
&& si->playerInfos[player].castle == VLC->heroh->objects[ID]->heroClass->faction
|
return false;
|
||||||
&& !vstd::contains(getUsedHeroes(), ID)
|
|
||||||
&& mi->mapHeader->allowedHeroes.count(ID);
|
if (ID >= VLC->heroh->size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (si->playerInfos[player].castle != VLC->heroh->objects[ID]->heroClass->faction)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (vstd::contains(getUsedHeroes(), ID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!mi->mapHeader->allowedHeroes.count(ID))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (const auto & disposedHero : mi->mapHeader->disposedHeroes)
|
||||||
|
if (disposedHero.heroId == ID && !disposedHero.players.count(player))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<HeroTypeID> CVCMIServer::getUsedHeroes()
|
std::vector<HeroTypeID> CVCMIServer::getUsedHeroes()
|
||||||
|
@ -180,12 +180,12 @@ void MapComparer::compareHeader()
|
|||||||
boost::sort (expectedEvents, sortByIdentifier);
|
boost::sort (expectedEvents, sortByIdentifier);
|
||||||
|
|
||||||
checkEqual(actualEvents, expectedEvents);
|
checkEqual(actualEvents, expectedEvents);
|
||||||
|
checkEqual(actual->disposedHeroes, expected->disposedHeroes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapComparer::compareOptions()
|
void MapComparer::compareOptions()
|
||||||
{
|
{
|
||||||
checkEqual(actual->rumors, expected->rumors);
|
checkEqual(actual->rumors, expected->rumors);
|
||||||
checkEqual(actual->disposedHeroes, expected->disposedHeroes);
|
|
||||||
//todo: compareOptions predefinedHeroes
|
//todo: compareOptions predefinedHeroes
|
||||||
|
|
||||||
checkEqual(actual->allowedAbilities, expected->allowedAbilities);
|
checkEqual(actual->allowedAbilities, expected->allowedAbilities);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user