mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +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:
parent
9ec299931d
commit
b8eddcd9a8
@ -311,7 +311,7 @@ Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec)
|
||||
setPriority(g);
|
||||
}
|
||||
|
||||
auto compareGoals = [&](Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
|
||||
auto compareGoals = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
|
||||
{
|
||||
return lhs->priority < rhs->priority;
|
||||
};
|
||||
@ -467,4 +467,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
|
||||
void FuzzyHelper::setPriority (Goals::TSubgoal & g)
|
||||
{
|
||||
g->setpriority(g->accept(this)); //this enforces returned value is set
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ public:
|
||||
const CGTownInstance *findTownWithTavern() const;
|
||||
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
|
||||
|
||||
bool VCAI::canAct (HeroPtr h) const;
|
||||
bool canAct(HeroPtr h) const;
|
||||
std::vector<HeroPtr> getUnblockedHeroes() const;
|
||||
HeroPtr primaryHero() const;
|
||||
TResources freeResources() const; //owned resources minus gold reserve
|
||||
|
27
Global.h
27
Global.h
@ -225,6 +225,28 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* VCMI standard library */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
#include "lib/logging/CLogger.h"
|
||||
|
||||
void inline handleException()
|
||||
{
|
||||
try
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch(const std::exception & ex)
|
||||
{
|
||||
logGlobal->errorStream() << ex.what();
|
||||
}
|
||||
catch(const std::string & ex)
|
||||
{
|
||||
logGlobal->errorStream() << ex;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
logGlobal->errorStream() << "Sorry, caught unknown exception type. No more info available.";
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream & operator<<(std::ostream & out, const boost::optional<T> & opt)
|
||||
{
|
||||
@ -601,8 +623,3 @@ namespace vstd
|
||||
}
|
||||
using vstd::operator-=;
|
||||
using vstd::make_unique;
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* VCMI headers */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
#include "lib/logging/CLogger.h"
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -457,15 +457,16 @@ private:
|
||||
void randomizeMapObjects();
|
||||
void randomizeObject(CGObjectInstance *cur);
|
||||
void initPlayerStates();
|
||||
void initHeroPlaceholders();
|
||||
void placeCampaignHeroes();
|
||||
const CCampaignScenario * getCampaignScenarioForCrossoverHeroes() const;
|
||||
std::vector<CGHeroInstance *> prepareCrossoverHeroes(const CCampaignScenario * campaignScenario);
|
||||
|
||||
// returns heroes and placeholders in where heroes will be put
|
||||
std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > generateCampaignHeroesToReplace(std::vector<CGHeroInstance *> & crossoverHeroes);
|
||||
|
||||
void placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements);
|
||||
void replaceHeroesPlaceholders(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements);
|
||||
void placeStartingHeroes();
|
||||
void placeStartingHero(PlayerColor playerColor, HeroTypeID heroTypeId, int3 townPos);
|
||||
void initStartingResources();
|
||||
void initHeroes();
|
||||
void giveCampaignBonusToHero(CGHeroInstance * hero);
|
||||
@ -494,7 +495,8 @@ private:
|
||||
bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
|
||||
std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const;
|
||||
std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
|
||||
int pickHero(PlayerColor owner);
|
||||
int pickUnusedHeroTypeRandomly(PlayerColor owner) const; // picks a unused hero type randomly
|
||||
int pickNextHeroType(PlayerColor owner) const; // picks next free hero type of the H3 hero init sequence -> chosen starting hero, then unused hero type randomly
|
||||
|
||||
friend class CCallback;
|
||||
friend class CClient;
|
||||
|
@ -32,6 +32,10 @@
|
||||
|
||||
#include "../lib/UnlockGuard.h"
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
std::string NAME_AFFIX = "server";
|
||||
std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
|
||||
using namespace boost;
|
||||
@ -531,8 +535,41 @@ static void handleCommandOptions(int argc, char *argv[])
|
||||
po::notify(cmdLineOptions);
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
void handleLinuxSignal(int sig)
|
||||
{
|
||||
const int STACKTRACE_SIZE = 100;
|
||||
void * buffer[STACKTRACE_SIZE];
|
||||
int ptrCount = backtrace(buffer, STACKTRACE_SIZE);
|
||||
char ** strings;
|
||||
|
||||
logGlobal->errorStream() << "Error: signal " << sig << ":";
|
||||
strings = backtrace_symbols(buffer, ptrCount);
|
||||
if(strings == nullptr)
|
||||
{
|
||||
logGlobal->errorStream() << "There are no symbols.";
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < ptrCount; ++i)
|
||||
{
|
||||
logGlobal->errorStream() << strings[i];
|
||||
}
|
||||
free(strings);
|
||||
}
|
||||
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// Installs a sig sev segmentation violation handler
|
||||
// to log stacktrace
|
||||
#ifdef __GNUC__
|
||||
signal(SIGSEGV, handleLinuxSignal);
|
||||
#endif
|
||||
|
||||
console = new CConsoleHandler;
|
||||
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console);
|
||||
logConfig.configureDefault();
|
||||
@ -564,7 +601,11 @@ int main(int argc, char** argv)
|
||||
{
|
||||
logNetwork->errorStream() << e.what();
|
||||
end2 = true;
|
||||
}HANDLE_EXCEPTION
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
handleException();
|
||||
}
|
||||
}
|
||||
catch(boost::system::system_error &e)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user