mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-29 00:41:38 +02:00
- Moved place bonus hero before normal random hero and starting hero placement -> same behaviour as in OH3
- Moved placing campaign heroes before random object generation -> same behaviour as in OH3 - Refactored pickHero into pickNextHeroType (hero generation sequence) and pickUnusedHeroTypeRandomly - Added a SIGSEV violation handler to vcmiserver executable for logging stacktrace (for convenience only) - Fixed Fuzzy.cpp and VCAI.h compilation on Clang - Added a handleException function in addition to our macros (no use of macros, enables debugging support, does not re-throw, catches ...-case too)
This commit is contained in:
@ -26,6 +26,7 @@
|
||||
#include "GameConstants.h"
|
||||
#include "rmg/CMapGenerator.h"
|
||||
#include "CStopWatch.h"
|
||||
#include "mapping/CMapEditManager.h"
|
||||
|
||||
DLL_LINKAGE std::minstd_rand ran;
|
||||
class CGObjectInstance;
|
||||
@ -444,28 +445,23 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CGameState::pickHero(PlayerColor owner)
|
||||
int CGameState::pickNextHeroType(PlayerColor owner) const
|
||||
{
|
||||
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
|
||||
if(!isUsedHero(HeroTypeID(ps.hero)) && ps.hero >= 0) //we haven't used selected hero
|
||||
return ps.hero;
|
||||
|
||||
if(scenarioOps->mode == StartInfo::CAMPAIGN)
|
||||
if(ps.hero >= 0 && !isUsedHero(HeroTypeID(ps.hero))) //we haven't used selected hero
|
||||
{
|
||||
auto bonus = scenarioOps->campState->getBonusForCurrentMap();
|
||||
if(bonus && bonus->type == CScenarioTravel::STravelBonus::HERO && owner == PlayerColor(bonus->info1))
|
||||
{
|
||||
//TODO what if hero chosen as bonus is placed in the prison on map
|
||||
if(bonus->info2 != 0xffff && !isUsedHero(HeroTypeID(bonus->info2))) //not random and not taken
|
||||
{
|
||||
return bonus->info2;
|
||||
}
|
||||
}
|
||||
return ps.hero;
|
||||
}
|
||||
|
||||
return pickUnusedHeroTypeRandomly(owner);
|
||||
}
|
||||
|
||||
int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner) const
|
||||
{
|
||||
//list of available heroes for this faction and others
|
||||
std::vector<HeroTypeID> factionHeroes, otherHeroes;
|
||||
|
||||
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
|
||||
for(HeroTypeID hid : getUnusedAllowedHeroes())
|
||||
{
|
||||
if(VLC->heroh->heroes[hid.getNum()]->heroClass->faction == ps.castle)
|
||||
@ -507,7 +503,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
|
||||
case Obj::RANDOM_RELIC_ART:
|
||||
return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_RELIC));
|
||||
case Obj::RANDOM_HERO:
|
||||
return std::make_pair(Obj::HERO, pickHero(obj->tempOwner));
|
||||
return std::make_pair(Obj::HERO, pickNextHeroType(obj->tempOwner));
|
||||
case Obj::RANDOM_MONSTER:
|
||||
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran)));
|
||||
case Obj::RANDOM_MONSTER_L1:
|
||||
@ -794,11 +790,11 @@ void CGameState::init(StartInfo * si)
|
||||
|
||||
logGlobal->debugStream() << "Initialization:";
|
||||
|
||||
initPlayerStates();
|
||||
placeCampaignHeroes();
|
||||
initGrailPosition();
|
||||
initRandomFactionsForPlayers();
|
||||
randomizeMapObjects();
|
||||
initPlayerStates();
|
||||
initHeroPlaceholders();
|
||||
placeStartingHeroes();
|
||||
initStartingResources();
|
||||
initHeroes();
|
||||
@ -1095,10 +1091,31 @@ void CGameState::initPlayerStates()
|
||||
}
|
||||
}
|
||||
|
||||
void CGameState::initHeroPlaceholders()
|
||||
void CGameState::placeCampaignHeroes()
|
||||
{
|
||||
if (scenarioOps->campState)
|
||||
{
|
||||
// place bonus hero
|
||||
auto campaignBonus = scenarioOps->campState->getBonusForCurrentMap();
|
||||
bool campaignGiveHero = campaignBonus && campaignBonus.get().type == CScenarioTravel::STravelBonus::HERO;
|
||||
|
||||
if(campaignGiveHero)
|
||||
{
|
||||
auto playerColor = PlayerColor(campaignBonus->info1);
|
||||
auto it = scenarioOps->playerInfos.find(playerColor);
|
||||
if(it != scenarioOps->playerInfos.end())
|
||||
{
|
||||
auto heroTypeId = campaignBonus->info2;
|
||||
if(heroTypeId == 0xffff) // random bonus hero
|
||||
{
|
||||
heroTypeId = pickUnusedHeroTypeRandomly(playerColor);
|
||||
}
|
||||
|
||||
placeStartingHero(playerColor, HeroTypeID(heroTypeId), map->players[playerColor.getNum()].posOfMainTown);
|
||||
}
|
||||
}
|
||||
|
||||
// replace heroes placeholders
|
||||
auto campaignScenario = getCampaignScenarioForCrossoverHeroes();
|
||||
|
||||
if(campaignScenario)
|
||||
@ -1107,14 +1124,29 @@ void CGameState::initHeroPlaceholders()
|
||||
auto crossoverHeroes = prepareCrossoverHeroes(campaignScenario);
|
||||
|
||||
logGlobal->debugStream() << "\tGenerate list of hero placeholders";
|
||||
auto campaignHeroReplacements = generateCampaignHeroesToReplace(crossoverHeroes);
|
||||
const auto campaignHeroReplacements = generateCampaignHeroesToReplace(crossoverHeroes);
|
||||
|
||||
// remove same heroes on the map which will be added through crossover heroes
|
||||
/*for(auto & campaignHeroReplacement : campaignHeroReplacement)
|
||||
{
|
||||
campaignHeroReplacement.first->subID
|
||||
}*/
|
||||
|
||||
logGlobal->debugStream() << "\tReplace placeholders with heroes";
|
||||
placeCampaignHeroes(campaignHeroReplacements);
|
||||
replaceHeroesPlaceholders(campaignHeroReplacements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameState::placeStartingHero(PlayerColor playerColor, HeroTypeID heroTypeId, int3 townPos)
|
||||
{
|
||||
townPos.x += 1;
|
||||
|
||||
CGHeroInstance * hero = static_cast<CGHeroInstance*>(createObject(Obj::HERO, heroTypeId.getNum(), townPos, playerColor));
|
||||
hero->initHero();
|
||||
map->getEditManager()->insertObject(hero, townPos);
|
||||
}
|
||||
|
||||
const CCampaignScenario * CGameState::getCampaignScenarioForCrossoverHeroes() const
|
||||
{
|
||||
const CCampaignScenario * campaignScenario = nullptr;
|
||||
@ -1223,36 +1255,26 @@ std::vector<CGHeroInstance *> CGameState::prepareCrossoverHeroes(const CCampaign
|
||||
void CGameState::placeStartingHeroes()
|
||||
{
|
||||
logGlobal->debugStream() << "\tGiving starting hero";
|
||||
bool campaignGiveHero = false;
|
||||
if(scenarioOps->campState)
|
||||
|
||||
for(auto & playerSettingPair : scenarioOps->playerInfos)
|
||||
{
|
||||
if(auto bonus = scenarioOps->campState->getBonusForCurrentMap())
|
||||
auto playerColor = playerSettingPair.first;
|
||||
auto & playerInfo = map->players[playerColor.getNum()];
|
||||
if(playerInfo.generateHeroAtMainTown && playerInfo.hasMainTown)
|
||||
{
|
||||
campaignGiveHero = scenarioOps->mode == StartInfo::CAMPAIGN &&
|
||||
bonus.get().type == CScenarioTravel::STravelBonus::HERO;
|
||||
}
|
||||
}
|
||||
// Do not place a starting hero if the hero was already placed due to a campaign bonus
|
||||
if(scenarioOps->campState)
|
||||
{
|
||||
if(auto campaignBonus = scenarioOps->campState->getBonusForCurrentMap())
|
||||
{
|
||||
if(campaignBonus->type == CScenarioTravel::STravelBonus::HERO && playerColor == PlayerColor(campaignBonus->info1)) continue;
|
||||
}
|
||||
}
|
||||
|
||||
for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it)
|
||||
{
|
||||
const PlayerInfo &p = map->players[it->first.getNum()];
|
||||
bool generateHero = (p.generateHeroAtMainTown ||
|
||||
(it->second.playerID != PlayerSettings::PLAYER_AI && campaignGiveHero)) && p.hasMainTown;
|
||||
if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first))
|
||||
{
|
||||
int3 hpos = p.posOfMainTown;
|
||||
hpos.x+=1;
|
||||
int heroTypeId = pickNextHeroType(playerColor);
|
||||
if(playerSettingPair.second.hero == -1) playerSettingPair.second.hero = heroTypeId;
|
||||
|
||||
int h = pickHero(it->first);
|
||||
if(it->second.hero == -1)
|
||||
it->second.hero = h;
|
||||
|
||||
CGHeroInstance * nnn = static_cast<CGHeroInstance*>(createObject(Obj::HERO,h,hpos,it->first));
|
||||
nnn->id = ObjectInstanceID(map->objects.size());
|
||||
nnn->initHero();
|
||||
map->heroesOnMap.push_back(nnn);
|
||||
map->objects.push_back(nnn);
|
||||
map->addBlockVisTiles(nnn);
|
||||
placeStartingHero(playerColor, HeroTypeID(heroTypeId), playerInfo.posOfMainTown);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2781,7 +2803,7 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::generateC
|
||||
return campaignHeroReplacements;
|
||||
}
|
||||
|
||||
void CGameState::placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements)
|
||||
void CGameState::replaceHeroesPlaceholders(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements)
|
||||
{
|
||||
for(auto obj : campHeroReplacements)
|
||||
{
|
||||
|
Reference in New Issue
Block a user