1
0
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:
beegee1 2013-12-28 12:47:55 +00:00
parent 9ec299931d
commit b8eddcd9a8
6 changed files with 141 additions and 59 deletions

View File

@ -311,7 +311,7 @@ Goals::TSubgoal FuzzyHelper::chooseSolution (Goals::TGoalVec vec)
setPriority(g); 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; return lhs->priority < rhs->priority;
}; };
@ -467,4 +467,4 @@ float FuzzyHelper::evaluate (Goals::AbstractGoal & g)
void FuzzyHelper::setPriority (Goals::TSubgoal & g) void FuzzyHelper::setPriority (Goals::TSubgoal & g)
{ {
g->setpriority(g->accept(this)); //this enforces returned value is set g->setpriority(g->accept(this)); //this enforces returned value is set
} }

View File

@ -295,7 +295,7 @@ public:
const CGTownInstance *findTownWithTavern() const; const CGTownInstance *findTownWithTavern() const;
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const; bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
bool VCAI::canAct (HeroPtr h) const; bool canAct(HeroPtr h) const;
std::vector<HeroPtr> getUnblockedHeroes() const; std::vector<HeroPtr> getUnblockedHeroes() const;
HeroPtr primaryHero() const; HeroPtr primaryHero() const;
TResources freeResources() const; //owned resources minus gold reserve TResources freeResources() const; //owned resources minus gold reserve

View File

@ -225,6 +225,28 @@ template<typename T, size_t N> char (&_ArrayCountObj(const T (&)[N]))[N];
/* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */
/* VCMI standard library */ /* 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> template<typename T>
std::ostream & operator<<(std::ostream & out, const boost::optional<T> & opt) std::ostream & operator<<(std::ostream & out, const boost::optional<T> & opt)
{ {
@ -601,8 +623,3 @@ namespace vstd
} }
using vstd::operator-=; using vstd::operator-=;
using vstd::make_unique; using vstd::make_unique;
/* ---------------------------------------------------------------------------- */
/* VCMI headers */
/* ---------------------------------------------------------------------------- */
#include "lib/logging/CLogger.h"

View File

@ -26,6 +26,7 @@
#include "GameConstants.h" #include "GameConstants.h"
#include "rmg/CMapGenerator.h" #include "rmg/CMapGenerator.h"
#include "CStopWatch.h" #include "CStopWatch.h"
#include "mapping/CMapEditManager.h"
DLL_LINKAGE std::minstd_rand ran; DLL_LINKAGE std::minstd_rand ran;
class CGObjectInstance; class CGObjectInstance;
@ -444,28 +445,23 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, PlayerColor pl
return ret; return ret;
} }
int CGameState::pickHero(PlayerColor owner) int CGameState::pickNextHeroType(PlayerColor owner) const
{ {
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner); const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
if(!isUsedHero(HeroTypeID(ps.hero)) && ps.hero >= 0) //we haven't used selected hero if(ps.hero >= 0 && !isUsedHero(HeroTypeID(ps.hero))) //we haven't used selected hero
return ps.hero;
if(scenarioOps->mode == StartInfo::CAMPAIGN)
{ {
auto bonus = scenarioOps->campState->getBonusForCurrentMap(); return ps.hero;
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 pickUnusedHeroTypeRandomly(owner);
}
int CGameState::pickUnusedHeroTypeRandomly(PlayerColor owner) const
{
//list of available heroes for this faction and others //list of available heroes for this faction and others
std::vector<HeroTypeID> factionHeroes, otherHeroes; std::vector<HeroTypeID> factionHeroes, otherHeroes;
const PlayerSettings &ps = scenarioOps->getIthPlayersSettings(owner);
for(HeroTypeID hid : getUnusedAllowedHeroes()) for(HeroTypeID hid : getUnusedAllowedHeroes())
{ {
if(VLC->heroh->heroes[hid.getNum()]->heroClass->faction == ps.castle) 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: case Obj::RANDOM_RELIC_ART:
return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_RELIC)); return std::make_pair(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_RELIC));
case Obj::RANDOM_HERO: 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: case Obj::RANDOM_MONSTER:
return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran))); return std::make_pair(Obj::MONSTER, VLC->creh->pickRandomMonster(std::ref(ran)));
case Obj::RANDOM_MONSTER_L1: case Obj::RANDOM_MONSTER_L1:
@ -794,11 +790,11 @@ void CGameState::init(StartInfo * si)
logGlobal->debugStream() << "Initialization:"; logGlobal->debugStream() << "Initialization:";
initPlayerStates();
placeCampaignHeroes();
initGrailPosition(); initGrailPosition();
initRandomFactionsForPlayers(); initRandomFactionsForPlayers();
randomizeMapObjects(); randomizeMapObjects();
initPlayerStates();
initHeroPlaceholders();
placeStartingHeroes(); placeStartingHeroes();
initStartingResources(); initStartingResources();
initHeroes(); initHeroes();
@ -1095,10 +1091,31 @@ void CGameState::initPlayerStates()
} }
} }
void CGameState::initHeroPlaceholders() void CGameState::placeCampaignHeroes()
{ {
if (scenarioOps->campState) 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(); auto campaignScenario = getCampaignScenarioForCrossoverHeroes();
if(campaignScenario) if(campaignScenario)
@ -1107,14 +1124,29 @@ void CGameState::initHeroPlaceholders()
auto crossoverHeroes = prepareCrossoverHeroes(campaignScenario); auto crossoverHeroes = prepareCrossoverHeroes(campaignScenario);
logGlobal->debugStream() << "\tGenerate list of hero placeholders"; 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"; 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 * CGameState::getCampaignScenarioForCrossoverHeroes() const
{ {
const CCampaignScenario * campaignScenario = nullptr; const CCampaignScenario * campaignScenario = nullptr;
@ -1223,36 +1255,26 @@ std::vector<CGHeroInstance *> CGameState::prepareCrossoverHeroes(const CCampaign
void CGameState::placeStartingHeroes() void CGameState::placeStartingHeroes()
{ {
logGlobal->debugStream() << "\tGiving starting hero"; 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 && // Do not place a starting hero if the hero was already placed due to a campaign bonus
bonus.get().type == CScenarioTravel::STravelBonus::HERO; 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) int heroTypeId = pickNextHeroType(playerColor);
{ if(playerSettingPair.second.hero == -1) playerSettingPair.second.hero = heroTypeId;
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 h = pickHero(it->first); placeStartingHero(playerColor, HeroTypeID(heroTypeId), playerInfo.posOfMainTown);
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);
} }
} }
} }
@ -2781,7 +2803,7 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::generateC
return campaignHeroReplacements; 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) for(auto obj : campHeroReplacements)
{ {

View File

@ -457,15 +457,16 @@ private:
void randomizeMapObjects(); void randomizeMapObjects();
void randomizeObject(CGObjectInstance *cur); void randomizeObject(CGObjectInstance *cur);
void initPlayerStates(); void initPlayerStates();
void initHeroPlaceholders(); void placeCampaignHeroes();
const CCampaignScenario * getCampaignScenarioForCrossoverHeroes() const; const CCampaignScenario * getCampaignScenarioForCrossoverHeroes() const;
std::vector<CGHeroInstance *> prepareCrossoverHeroes(const CCampaignScenario * campaignScenario); std::vector<CGHeroInstance *> prepareCrossoverHeroes(const CCampaignScenario * campaignScenario);
// returns heroes and placeholders in where heroes will be put // returns heroes and placeholders in where heroes will be put
std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > generateCampaignHeroesToReplace(std::vector<CGHeroInstance *> & crossoverHeroes); 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 placeStartingHeroes();
void placeStartingHero(PlayerColor playerColor, HeroTypeID heroTypeId, int3 townPos);
void initStartingResources(); void initStartingResources();
void initHeroes(); void initHeroes();
void giveCampaignBonusToHero(CGHeroInstance * hero); void giveCampaignBonusToHero(CGHeroInstance * hero);
@ -494,7 +495,8 @@ private:
bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const; 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> 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 CCallback;
friend class CClient; friend class CClient;

View File

@ -32,6 +32,10 @@
#include "../lib/UnlockGuard.h" #include "../lib/UnlockGuard.h"
#ifdef __GNUC__
#include <execinfo.h>
#endif
std::string NAME_AFFIX = "server"; std::string NAME_AFFIX = "server";
std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
using namespace boost; using namespace boost;
@ -531,8 +535,41 @@ static void handleCommandOptions(int argc, char *argv[])
po::notify(cmdLineOptions); 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) 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; console = new CConsoleHandler;
CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console); CBasicLogConfigurator logConfig(VCMIDirs::get().userCachePath() + "/VCMI_Server_log.txt", console);
logConfig.configureDefault(); logConfig.configureDefault();
@ -564,7 +601,11 @@ int main(int argc, char** argv)
{ {
logNetwork->errorStream() << e.what(); logNetwork->errorStream() << e.what();
end2 = true; end2 = true;
}HANDLE_EXCEPTION }
catch(...)
{
handleException();
}
} }
catch(boost::system::system_error &e) catch(boost::system::system_error &e)
{ {