1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

- Refactored method CGameState::init

This commit is contained in:
beegee1
2013-12-18 18:18:12 +00:00
parent 61fc216a6f
commit f0cbbbdb70
7 changed files with 836 additions and 773 deletions

View File

@ -699,7 +699,6 @@ int CClient::sendRequest(const CPack *request, PlayerColor player)
void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp ) void CClient::campaignMapFinished( shared_ptr<CCampaignState> camp )
{ {
endGame(false); endGame(false);
LOCPLINT = nullptr; //TODO free res
GH.curInt = CGPreGame::create(); GH.curInt = CGPreGame::create();
auto & epilogue = camp->camp->scenarios[camp->mapsConquered.back()].epilog; auto & epilogue = camp->camp->scenarios[camp->mapsConquered.back()].epilog;

View File

@ -726,6 +726,7 @@ int CGameState::getDate(Date::EDateType mode) const
} }
return 0; return 0;
} }
CGameState::CGameState() CGameState::CGameState()
{ {
gs = this; gs = this;
@ -735,6 +736,7 @@ CGameState::CGameState()
objCaller = new CObjectCallersHandler; objCaller = new CObjectCallersHandler;
globalEffects.setDescription("Global effects"); globalEffects.setDescription("Global effects");
} }
CGameState::~CGameState() CGameState::~CGameState()
{ {
//delete mx;//TODO: crash on Linux (mutex must be unlocked before destruction) //delete mx;//TODO: crash on Linux (mutex must be unlocked before destruction)
@ -762,76 +764,6 @@ BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2],
void CGameState::init(StartInfo * si) void CGameState::init(StartInfo * si)
{ {
auto giveCampaignBonusToHero = [&](CGHeroInstance * hero)
{
const boost::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
if(!curBonus)
return;
if(curBonus->isBonusForHero())
{
//apply bonus
switch (curBonus->type)
{
case CScenarioTravel::STravelBonus::SPELL:
hero->spells.insert(SpellID(curBonus->info2));
break;
case CScenarioTravel::STravelBonus::MONSTER:
{
for(int i=0; i<GameConstants::ARMY_SIZE; i++)
{
if(hero->slotEmpty(SlotID(i)))
{
hero->addToSlot(SlotID(i), CreatureID(curBonus->info2), curBonus->info3);
break;
}
}
}
break;
case CScenarioTravel::STravelBonus::ARTIFACT:
gs->giveHeroArtifact(hero, static_cast<ArtifactID>(curBonus->info2));
break;
case CScenarioTravel::STravelBonus::SPELL_SCROLL:
{
CArtifactInstance * scroll = CArtifactInstance::createScroll(SpellID(curBonus->info2).toSpell());
scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
}
break;
case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
{
const ui8* ptr = reinterpret_cast<const ui8*>(&curBonus->info2);
for (int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
{
int val = ptr[g];
if (val == 0)
{
continue;
}
auto bb = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, *scenarioOps->campState->currentMap, g);
hero->addNewBonus(bb);
}
}
break;
case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
hero->setSecSkillLevel(SecondarySkill(curBonus->info2), curBonus->info3, true);
break;
}
}
};
auto getHumanPlayerInfo = [&]() -> std::vector<const PlayerSettings *>
{
std::vector<const PlayerSettings *> ret;
for(auto it = scenarioOps->playerInfos.cbegin();
it != scenarioOps->playerInfos.cend(); ++it)
{
if(it->second.playerID != PlayerSettings::PLAYER_AI)
ret.push_back(&it->second);
}
return ret;
};
logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed; logGlobal->infoStream() << "\tUsing random seed: "<< si->seedToBeUsed;
ran.seed((boost::int32_t)si->seedToBeUsed); ran.seed((boost::int32_t)si->seedToBeUsed);
scenarioOps = new StartInfo(*si); scenarioOps = new StartInfo(*si);
@ -841,6 +773,59 @@ void CGameState::init(StartInfo * si)
switch(scenarioOps->mode) switch(scenarioOps->mode)
{ {
case StartInfo::NEW_GAME: case StartInfo::NEW_GAME:
initNewGame();
break;
case StartInfo::CAMPAIGN:
initCampaign();
break;
case StartInfo::DUEL:
initDuel();
return;
default:
logGlobal->errorStream() << "Wrong mode: " << (int)scenarioOps->mode;
return;
}
VLC->arth->initAllowedArtifactsList(map->allowedArtifact);
logGlobal->infoStream() << "Map loaded!";
checkMapChecksum();
day = 0;
logGlobal->debugStream() << "Initialization:";
initGrailPosition();
initRandomFactionsForPlayers();
randomizeMapObjects();
initPlayerStates();
initHeroPlaceholders();
placeStartingHeroes();
initStartingResources();
initHeroes();
initFogOfWar();
initStartingBonus();
initTowns();
initMapObjects();
buildBonusSystemTree();
initVisitingAndGarrisonedHeroes();
logGlobal->debugStream() << "\tChecking objectives";
map->checkForObjectives(); //needs to be run when all objects are properly placed
int seedAfterInit = ran();
logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
if(scenarioOps->seedPostInit > 0)
{
//RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
assert(scenarioOps->seedPostInit == seedAfterInit);
}
else
{
scenarioOps->seedPostInit = seedAfterInit; //store the post init "seed"
}
}
void CGameState::initNewGame()
{ {
if(scenarioOps->createRandomMap()) if(scenarioOps->createRandomMap())
{ {
@ -881,8 +866,8 @@ void CGameState::init(StartInfo * si)
map = CMapService::loadMap(scenarioOps->mapname).release(); map = CMapService::loadMap(scenarioOps->mapname).release();
} }
} }
break;
case StartInfo::CAMPAIGN: void CGameState::initCampaign()
{ {
logGlobal->infoStream() << "Open campaign map file: " << scenarioOps->campState->currentMap; logGlobal->infoStream() << "Open campaign map file: " << scenarioOps->campState->currentMap;
auto campaign = scenarioOps->campState; auto campaign = scenarioOps->campState;
@ -892,17 +877,110 @@ void CGameState::init(StartInfo * si)
auto buffer = reinterpret_cast<const ui8 *>(mapContent.data()); auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
map = CMapService::loadMap(buffer, mapContent.size()).release(); map = CMapService::loadMap(buffer, mapContent.size()).release();
} }
break;
case StartInfo::DUEL:
initDuel();
return;
default:
logGlobal->errorStream() << "Wrong mode: " << (int)scenarioOps->mode;
return;
}
VLC->arth->initAllowedArtifactsList(map->allowedArtifact);
logGlobal->infoStream() << "Map loaded!";
void CGameState::initDuel()
{
DuelParameters dp;
try //CLoadFile likes throwing
{
if(boost::algorithm::ends_with(scenarioOps->mapname, ".json"))
{
logGlobal->infoStream() << "Loading duel settings from JSON file: " << scenarioOps->mapname;
dp = DuelParameters::fromJSON(scenarioOps->mapname);
logGlobal->infoStream() << "JSON file has been successfully read!";
}
else
{
CLoadFile lf(scenarioOps->mapname);
lf >> dp;
}
}
catch(...)
{
logGlobal->errorStream() << "Cannot load duel settings from " << scenarioOps->mapname;
throw;
}
const CArmedInstance *armies[2] = {nullptr};
const CGHeroInstance *heroes[2] = {nullptr};
CGTownInstance *town = nullptr;
for(int i = 0; i < 2; i++)
{
CArmedInstance *obj = nullptr;
if(dp.sides[i].heroId >= 0)
{
const DuelParameters::SideSettings &ss = dp.sides[i];
auto h = new CGHeroInstance();
armies[i] = heroes[i] = h;
obj = h;
h->subID = ss.heroId;
for(int i = 0; i < ss.heroPrimSkills.size(); i++)
h->pushPrimSkill(static_cast<PrimarySkill::PrimarySkill>(i), ss.heroPrimSkills[i]);
if(!ss.spells.empty())
{
h->putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
boost::copy(ss.spells, std::inserter(h->spells, h->spells.begin()));
}
for(auto &parka : ss.artifacts)
{
h->putArtifact(ArtifactPosition(parka.first), parka.second);
}
typedef const std::pair<si32, si8> &TSecSKill;
for(TSecSKill secSkill : ss.heroSecSkills)
h->setSecSkillLevel(SecondarySkill(secSkill.first), secSkill.second, 1);
h->initHero(HeroTypeID(h->subID));
obj->initObj();
}
else
{
auto c = new CGCreature();
armies[i] = obj = c;
//c->subID = 34;
}
obj->setOwner(PlayerColor(i));
for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++)
{
CreatureID cre = dp.sides[i].stacks[j].type;
TQuantity count = dp.sides[i].stacks[j].count;
if(count || obj->hasStackAtSlot(SlotID(j)))
obj->setCreature(SlotID(j), cre, count);
}
for(const DuelParameters::CusomCreature &cc : dp.creatures)
{
CCreature *c = VLC->creh->creatures[cc.id];
if(cc.attack >= 0)
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK))->val = cc.attack;
if(cc.defense >= 0)
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))->val = cc.defense;
if(cc.speed >= 0)
c->getBonusLocalFirst(Selector::type(Bonus::STACKS_SPEED))->val = cc.speed;
if(cc.HP >= 0)
c->getBonusLocalFirst(Selector::type(Bonus::STACK_HEALTH))->val = cc.HP;
if(cc.dmg >= 0)
{
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1))->val = cc.dmg;
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2))->val = cc.dmg;
}
if(cc.shoots >= 0)
c->getBonusLocalFirst(Selector::type(Bonus::SHOTS))->val = cc.shoots;
}
}
curB = BattleInfo::setupBattle(int3(), dp.terType, dp.bfieldType, armies, heroes, false, town);
curB->obstacles = dp.obstacles;
curB->localInit();
}
void CGameState::checkMapChecksum()
{
logGlobal->infoStream() << "\tOur checksum for the map: "<< map->checksum; logGlobal->infoStream() << "\tOur checksum for the map: "<< map->checksum;
if(scenarioOps->mapfileChecksum) if(scenarioOps->mapfileChecksum)
{ {
@ -914,11 +992,13 @@ void CGameState::init(StartInfo * si)
} }
} }
else else
{
scenarioOps->mapfileChecksum = map->checksum; scenarioOps->mapfileChecksum = map->checksum;
}
}
day = 0; void CGameState::initGrailPosition()
{
logGlobal->debugStream() << "Initialization:";
logGlobal->debugStream() << "\tPicking grail position"; logGlobal->debugStream() << "\tPicking grail position";
//pick grail location //pick grail location
if(map->grailPos.x < 0 || map->grailRadious) //grail not set or set within a radius around some place if(map->grailPos.x < 0 || map->grailRadious) //grail not set or set within a radius around some place
@ -957,8 +1037,10 @@ void CGameState::init(StartInfo * si)
else else
logGlobal->warnStream() << "Warning: Grail cannot be placed, no appropriate tile found!"; logGlobal->warnStream() << "Warning: Grail cannot be placed, no appropriate tile found!";
} }
}
//picking random factions for players void CGameState::initRandomFactionsForPlayers()
{
logGlobal->debugStream() << "\tPicking random factions for players"; logGlobal->debugStream() << "\tPicking random factions for players";
for(auto & elem : scenarioOps->playerInfos) for(auto & elem : scenarioOps->playerInfos)
{ {
@ -971,29 +1053,35 @@ void CGameState::init(StartInfo * si)
elem.second.castle = *iter; elem.second.castle = *iter;
} }
} }
}
//randomizing objects void CGameState::randomizeMapObjects()
{
logGlobal->debugStream() << "\tRandomizing objects"; logGlobal->debugStream() << "\tRandomizing objects";
for(CGObjectInstance *obj : map->objects) for(CGObjectInstance *obj : map->objects)
{ {
if(!obj) if(!obj) continue;
continue;
randomizeObject(obj); randomizeObject(obj);
obj->hoverName = VLC->generaltexth->names[obj->ID]; obj->hoverName = VLC->generaltexth->names[obj->ID];
//handle Favouring Winds - mark tiles under it //handle Favouring Winds - mark tiles under it
if(obj->ID == Obj::FAVORABLE_WINDS) if(obj->ID == Obj::FAVORABLE_WINDS)
{
for (int i = 0; i < obj->getWidth() ; i++) for (int i = 0; i < obj->getWidth() ; i++)
{
for (int j = 0; j < obj->getHeight() ; j++) for (int j = 0; j < obj->getHeight() ; j++)
{ {
int3 pos = obj->pos - int3(i,j,0); int3 pos = obj->pos - int3(i,j,0);
if(map->isInTheMap(pos)) if(map->isInTheMap(pos)) map->getTile(pos).extTileFlags |= 128;
map->getTile(pos).extTileFlags |= 128; }
}
}
} }
} }
/*********creating players entries in gs****************************************/ void CGameState::initPlayerStates()
{
logGlobal->debugStream() << "\tCreating player entries in gs"; logGlobal->debugStream() << "\tCreating player entries in gs";
for(auto & elem : scenarioOps->playerInfos) for(auto & elem : scenarioOps->playerInfos)
{ {
@ -1005,8 +1093,10 @@ void CGameState::init(StartInfo * si)
teams[ins.second.team].players.insert(ins.first);//add player to team teams[ins.second.team].players.insert(ins.first);//add player to team
players.insert(ins); players.insert(ins);
} }
}
/*************************replace hero placeholders*****************************/ void CGameState::initHeroPlaceholders()
{
if (scenarioOps->campState) if (scenarioOps->campState)
{ {
logGlobal->debugStream() << "\tReplacing hero placeholders"; logGlobal->debugStream() << "\tReplacing hero placeholders";
@ -1015,11 +1105,11 @@ void CGameState::init(StartInfo * si)
logGlobal->debugStream() << "\tSetting up heroes"; logGlobal->debugStream() << "\tSetting up heroes";
placeCampaignHeroes(campHeroReplacements); placeCampaignHeroes(campHeroReplacements);
} }
}
void CGameState::placeStartingHeroes()
/*********give starting hero****************************************/
logGlobal->debugStream() << "\tGiving starting hero";
{ {
logGlobal->debugStream() << "\tGiving starting hero";
bool campaignGiveHero = false; bool campaignGiveHero = false;
if(scenarioOps->campState) if(scenarioOps->campState)
{ {
@ -1054,7 +1144,8 @@ void CGameState::init(StartInfo * si)
} }
} }
/******************RESOURCES****************************************************/ void CGameState::initStartingResources()
{
logGlobal->debugStream() << "\tSetting up resources"; logGlobal->debugStream() << "\tSetting up resources";
const JsonNode config(ResourceID("config/startres.json")); const JsonNode config(ResourceID("config/startres.json"));
const JsonVector &vector = config["difficulty"].Vector(); const JsonVector &vector = config["difficulty"].Vector();
@ -1073,6 +1164,19 @@ void CGameState::init(StartInfo * si)
p.resources = startresAI; p.resources = startresAI;
} }
auto getHumanPlayerInfo = [&]() -> std::vector<const PlayerSettings *>
{
std::vector<const PlayerSettings *> ret;
for(auto it = scenarioOps->playerInfos.cbegin();
it != scenarioOps->playerInfos.cend(); ++it)
{
if(it->second.playerID != PlayerSettings::PLAYER_AI)
ret.push_back(&it->second);
}
return ret;
};
//give start resource bonus in case of campaign //give start resource bonus in case of campaign
if (scenarioOps->mode == StartInfo::CAMPAIGN) if (scenarioOps->mode == StartInfo::CAMPAIGN)
{ {
@ -1106,9 +1210,10 @@ void CGameState::init(StartInfo * si)
} }
} }
} }
}
void CGameState::initHeroes()
/*************************HEROES INIT / POOL************************************************/ {
for(auto hero : map->heroesOnMap) //heroes instances initialization for(auto hero : map->heroesOnMap) //heroes instances initialization
{ {
if (hero->getOwner() == PlayerColor::UNFLAGGABLE) if (hero->getOwner() == PlayerColor::UNFLAGGABLE)
@ -1204,8 +1309,67 @@ void CGameState::init(StartInfo * si)
} }
} }
} }
}
/*************************FOG**OF**WAR******************************************/ void CGameState::giveCampaignBonusToHero(CGHeroInstance * hero)
{
const boost::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
if(!curBonus)
return;
if(curBonus->isBonusForHero())
{
//apply bonus
switch (curBonus->type)
{
case CScenarioTravel::STravelBonus::SPELL:
hero->spells.insert(SpellID(curBonus->info2));
break;
case CScenarioTravel::STravelBonus::MONSTER:
{
for(int i=0; i<GameConstants::ARMY_SIZE; i++)
{
if(hero->slotEmpty(SlotID(i)))
{
hero->addToSlot(SlotID(i), CreatureID(curBonus->info2), curBonus->info3);
break;
}
}
}
break;
case CScenarioTravel::STravelBonus::ARTIFACT:
gs->giveHeroArtifact(hero, static_cast<ArtifactID>(curBonus->info2));
break;
case CScenarioTravel::STravelBonus::SPELL_SCROLL:
{
CArtifactInstance * scroll = CArtifactInstance::createScroll(SpellID(curBonus->info2).toSpell());
scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
}
break;
case CScenarioTravel::STravelBonus::PRIMARY_SKILL:
{
const ui8* ptr = reinterpret_cast<const ui8*>(&curBonus->info2);
for (int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
{
int val = ptr[g];
if (val == 0)
{
continue;
}
auto bb = new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::CAMPAIGN_BONUS, val, *scenarioOps->campState->currentMap, g);
hero->addNewBonus(bb);
}
}
break;
case CScenarioTravel::STravelBonus::SECONDARY_SKILL:
hero->setSecSkillLevel(SecondarySkill(curBonus->info2), curBonus->info3, true);
break;
}
}
}
void CGameState::initFogOfWar()
{
logGlobal->debugStream() << "\tFog of war"; //FIXME: should be initialized after all bonuses are set logGlobal->debugStream() << "\tFog of war"; //FIXME: should be initialized after all bonuses are set
for(auto & elem : teams) for(auto & elem : teams)
{ {
@ -1234,7 +1398,10 @@ void CGameState::init(StartInfo * si)
} }
} }
} }
}
void CGameState::initStartingBonus()
{
logGlobal->debugStream() << "\tStarting bonuses"; logGlobal->debugStream() << "\tStarting bonuses";
for(auto & elem : players) for(auto & elem : players)
{ {
@ -1276,7 +1443,10 @@ void CGameState::init(StartInfo * si)
break; break;
} }
} }
/****************************TOWNS************************************************/ }
void CGameState::initTowns()
{
logGlobal->debugStream() << "\tTowns"; logGlobal->debugStream() << "\tTowns";
//campaign bonuses for towns //campaign bonuses for towns
@ -1415,7 +1585,10 @@ void CGameState::init(StartInfo * si)
if(vti->getOwner() != PlayerColor::NEUTRAL) if(vti->getOwner() != PlayerColor::NEUTRAL)
getPlayer(vti->getOwner())->towns.push_back(vti); getPlayer(vti->getOwner())->towns.push_back(vti);
} }
}
void CGameState::initMapObjects()
{
logGlobal->debugStream() << "\tObject initialization"; logGlobal->debugStream() << "\tObject initialization";
objCaller->preInit(); objCaller->preInit();
for(CGObjectInstance *obj : map->objects) for(CGObjectInstance *obj : map->objects)
@ -1440,9 +1613,10 @@ void CGameState::init(StartInfo * si)
} }
} }
CGTeleport::postInit(); //pairing subterranean gates CGTeleport::postInit(); //pairing subterranean gates
}
buildBonusSystemTree(); void CGameState::initVisitingAndGarrisonedHeroes()
{
for(auto k=players.begin(); k!=players.end(); ++k) for(auto k=players.begin(); k!=players.end(); ++k)
{ {
if(k->first==PlayerColor::NEUTRAL) if(k->first==PlayerColor::NEUTRAL)
@ -1468,124 +1642,6 @@ void CGameState::init(StartInfo * si)
} }
} }
} }
logGlobal->debugStream() << "\tChecking objectives";
map->checkForObjectives(); //needs to be run when all objects are properly placed
int seedAfterInit = ran();
logGlobal->infoStream() << "Seed after init is " << seedAfterInit << " (before was " << scenarioOps->seedToBeUsed << ")";
if(scenarioOps->seedPostInit > 0)
{
//RNG must be in the same state on all machines when initialization is done (otherwise we have desync)
assert(scenarioOps->seedPostInit == seedAfterInit);
}
else
{
scenarioOps->seedPostInit = seedAfterInit; //store the post init "seed"
}
}
void CGameState::initDuel()
{
DuelParameters dp;
try //CLoadFile likes throwing
{
if(boost::algorithm::ends_with(scenarioOps->mapname, ".json"))
{
logGlobal->infoStream() << "Loading duel settings from JSON file: " << scenarioOps->mapname;
dp = DuelParameters::fromJSON(scenarioOps->mapname);
logGlobal->infoStream() << "JSON file has been successfully read!";
}
else
{
CLoadFile lf(scenarioOps->mapname);
lf >> dp;
}
}
catch(...)
{
logGlobal->errorStream() << "Cannot load duel settings from " << scenarioOps->mapname;
throw;
}
const CArmedInstance *armies[2] = {nullptr};
const CGHeroInstance *heroes[2] = {nullptr};
CGTownInstance *town = nullptr;
for(int i = 0; i < 2; i++)
{
CArmedInstance *obj = nullptr;
if(dp.sides[i].heroId >= 0)
{
const DuelParameters::SideSettings &ss = dp.sides[i];
auto h = new CGHeroInstance();
armies[i] = heroes[i] = h;
obj = h;
h->subID = ss.heroId;
for(int i = 0; i < ss.heroPrimSkills.size(); i++)
h->pushPrimSkill(static_cast<PrimarySkill::PrimarySkill>(i), ss.heroPrimSkills[i]);
if(!ss.spells.empty())
{
h->putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
boost::copy(ss.spells, std::inserter(h->spells, h->spells.begin()));
}
for(auto &parka : ss.artifacts)
{
h->putArtifact(ArtifactPosition(parka.first), parka.second);
}
typedef const std::pair<si32, si8> &TSecSKill;
for(TSecSKill secSkill : ss.heroSecSkills)
h->setSecSkillLevel(SecondarySkill(secSkill.first), secSkill.second, 1);
h->initHero(HeroTypeID(h->subID));
obj->initObj();
}
else
{
auto c = new CGCreature();
armies[i] = obj = c;
//c->subID = 34;
}
obj->setOwner(PlayerColor(i));
for(int j = 0; j < ARRAY_COUNT(dp.sides[i].stacks); j++)
{
CreatureID cre = dp.sides[i].stacks[j].type;
TQuantity count = dp.sides[i].stacks[j].count;
if(count || obj->hasStackAtSlot(SlotID(j)))
obj->setCreature(SlotID(j), cre, count);
}
for(const DuelParameters::CusomCreature &cc : dp.creatures)
{
CCreature *c = VLC->creh->creatures[cc.id];
if(cc.attack >= 0)
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK))->val = cc.attack;
if(cc.defense >= 0)
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE))->val = cc.defense;
if(cc.speed >= 0)
c->getBonusLocalFirst(Selector::type(Bonus::STACKS_SPEED))->val = cc.speed;
if(cc.HP >= 0)
c->getBonusLocalFirst(Selector::type(Bonus::STACK_HEALTH))->val = cc.HP;
if(cc.dmg >= 0)
{
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 1))->val = cc.dmg;
c->getBonusLocalFirst(Selector::typeSubtype(Bonus::CREATURE_DAMAGE, 2))->val = cc.dmg;
}
if(cc.shoots >= 0)
c->getBonusLocalFirst(Selector::type(Bonus::SHOTS))->val = cc.shoots;
}
}
curB = BattleInfo::setupBattle(int3(), dp.terType, dp.bfieldType, armies, heroes, false, town);
curB->obstacles = dp.obstacles;
curB->localInit();
return;
} }
BFieldType CGameState::battleGetBattlefieldType(int3 tile) const BFieldType CGameState::battleGetBattlefieldType(int3 tile) const
@ -2555,14 +2611,12 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::campaignH
//selecting heroes by type //selecting heroes by type
for(int g=0; g<map->objects.size(); ++g) for(int g=0; g<map->objects.size(); ++g)
{ {
const ObjectInstanceID gid = ObjectInstanceID(g);
CGObjectInstance * obj = map->objects[g]; CGObjectInstance * obj = map->objects[g];
if (obj->ID != Obj::HERO_PLACEHOLDER) if (obj->ID == Obj::HERO_PLACEHOLDER)
{ {
continue;
}
CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj); CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
const ObjectInstanceID gid = ObjectInstanceID(g);
if(hp->subID != 0xFF) //select by type if(hp->subID != 0xFF) //select by type
{ {
bool found = false; bool found = false;
@ -2584,6 +2638,7 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::campaignH
} }
} }
} }
}
//selecting heroes by power //selecting heroes by power
@ -2594,14 +2649,12 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::campaignH
for(int g=0; g<map->objects.size(); ++g) for(int g=0; g<map->objects.size(); ++g)
{ {
const ObjectInstanceID gid = ObjectInstanceID(g);
CGObjectInstance * obj = map->objects[g]; CGObjectInstance * obj = map->objects[g];
if (obj->ID != Obj::HERO_PLACEHOLDER) if (obj->ID == Obj::HERO_PLACEHOLDER)
{ {
continue;
}
CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj); CGHeroPlaceholder * hp = static_cast<CGHeroPlaceholder*>(obj);
const ObjectInstanceID gid = ObjectInstanceID(g);
if (hp->subID == 0xFF) //select by power if (hp->subID == 0xFF) //select by power
{ {
if(Xheroes.size() > hp->power - 1) if(Xheroes.size() > hp->power - 1)
@ -2617,6 +2670,7 @@ std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > CGameState::campaignH
} }
} }
} }
}
return ret; return ret;
} }

View File

@ -29,11 +29,8 @@
*/ */
class CTown; class CTown;
class CScriptCallback;
class CCallback; class CCallback;
class IGameCallback; class IGameCallback;
class CLuaCallback;
class CCPPObjectScript;
class CCreatureSet; class CCreatureSet;
class CStack; class CStack;
class CQuest; class CQuest;
@ -388,15 +385,6 @@ DLL_LINKAGE std::ostream & operator<<(std::ostream & os, const EVictoryLossCheck
class DLL_LINKAGE CGameState : public CNonConstInfoCallback class DLL_LINKAGE CGameState : public CNonConstInfoCallback
{ {
public: public:
ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
PlayerColor currentPlayer; //ID of player currently having turn
ConstTransitivePtr<BattleInfo> curB; //current battle
ui32 day; //total number of days in game
ConstTransitivePtr<CMap> map;
std::map<PlayerColor, PlayerState> players;
std::map<TeamID, TeamState> teams;
CBonusSystemNode globalEffects;
struct DLL_LINKAGE HeroesPool struct DLL_LINKAGE HeroesPool
{ {
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > heroesPool; //[subID] - heroes available to buy; nullptr if not available std::map<ui32, ConstTransitivePtr<CGHeroInstance> > heroesPool; //[subID] - heroes available to buy; nullptr if not available
@ -410,18 +398,22 @@ public:
} }
} hpool; //we have here all heroes available on this map that are not hired } hpool; //we have here all heroes available on this map that are not hired
boost::shared_mutex *mx; CGameState();
virtual ~CGameState();
void init(StartInfo * si); void init(StartInfo * si);
bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
void placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements); PlayerColor currentPlayer; //ID of player currently having turn
std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > campaignHeroesToReplace(); //returns heroes and placeholders in where heroes will be put; may remove some placeholders ConstTransitivePtr<BattleInfo> curB; //current battle
std::set<HeroTypeID> getUnusedAllowedHeroes(bool alsoIncludeNotAllowed = false) const; ui32 day; //total number of days in game
void initDuel(); ConstTransitivePtr<CMap> map;
void randomizeObject(CGObjectInstance *cur); std::map<PlayerColor, PlayerState> players;
std::pair<Obj,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype> std::map<TeamID, TeamState> teams;
int pickHero(PlayerColor owner); CBonusSystemNode globalEffects;
boost::shared_mutex *mx;
void giveHeroArtifact(CGHeroInstance *h, ArtifactID aid); void giveHeroArtifact(CGHeroInstance *h, ArtifactID aid);
void apply(CPack *pack); void apply(CPack *pack);
@ -439,38 +431,65 @@ public:
std::map<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns std::map<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns
BattleInfo * setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town); BattleInfo * setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town);
void buildBonusSystemTree();
void attachArmedObjects();
void buildGlobalTeamPlayerTree();
void deserializationFix();
bool isVisible(int3 pos, PlayerColor player); bool isVisible(int3 pos, PlayerColor player);
bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player); bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> player);
CGameState(); //c-tor
virtual ~CGameState(); //d-tor
void getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing); void getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing);
int getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints=-1, bool checkLast=true); int getMovementCost(const CGHeroInstance *h, const int3 &src, const int3 &dest, int remainingMovePoints=-1, bool checkLast=true);
int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month int getDate(Date::EDateType mode=Date::DAY) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects; h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
BONUS_TREE_DESERIALIZATION_FIX BONUS_TREE_DESERIALIZATION_FIX
} }
friend class CCallback;
friend class CLuaCallback;
friend class CClient;
friend void initGameState(CMap * map, CGameInfo * cgi);
friend class IGameCallback;
friend class CMapHandler;
friend class CGameHandler;
private: private:
// Init game state
void initNewGame();
void initCampaign();
void initDuel();
void checkMapChecksum();
void initGrailPosition();
void initRandomFactionsForPlayers();
void randomizeMapObjects();
void randomizeObject(CGObjectInstance *cur);
void initPlayerStates();
void initHeroPlaceholders();
void placeCampaignHeroes(const std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > &campHeroReplacements);
void placeStartingHeroes();
void initStartingResources();
void initHeroes();
void giveCampaignBonusToHero(CGHeroInstance * hero);
void initFogOfWar();
void initStartingBonus();
void initTowns();
void initMapObjects();
void initVisitingAndGarrisonedHeroes();
// Victory / Loss condition checks
EVictoryLossCheckResult checkForVictory(PlayerColor player) const; //checks if given player is winner EVictoryLossCheckResult checkForVictory(PlayerColor player) const; //checks if given player is winner
EVictoryLossCheckResult checkForLoss(PlayerColor player) const; //checks if given player is loser EVictoryLossCheckResult checkForLoss(PlayerColor player) const; //checks if given player is loser
PlayerColor checkForStandardWin() const; //returns color of player that accomplished standard victory conditions or 255 (NEUTRAL) if no winner PlayerColor checkForStandardWin() const; //returns color of player that accomplished standard victory conditions or 255 (NEUTRAL) if no winner
bool checkForStandardLoss(PlayerColor player) const; //checks if given player lost the game bool checkForStandardLoss(PlayerColor player) const; //checks if given player lost the game
// Bonus system handling
void buildBonusSystemTree();
void attachArmedObjects();
void buildGlobalTeamPlayerTree();
void deserializationFix();
bool isUsedHero(HeroTypeID hid) const; //looks in heroes and prisons
std::vector<std::pair<CGHeroInstance*, ObjectInstanceID> > campaignHeroesToReplace(); //returns heroes and placeholders in where heroes will be put; may remove some placeholders
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);
friend class CCallback;
friend class CClient;
friend class IGameCallback;
friend class CMapHandler;
friend class CGameHandler;
}; };
struct DLL_LINKAGE QuestInfo //universal interface for human and AI struct DLL_LINKAGE QuestInfo //universal interface for human and AI

View File

@ -25,7 +25,6 @@ struct BattleInfo;
struct QuestInfo; struct QuestInfo;
class IGameCallback; class IGameCallback;
struct BattleResult; struct BattleResult;
class CCPPObjectScript;
class CGObjectInstance; class CGObjectInstance;
class CScript; class CScript;
class CObjectScript; class CObjectScript;

View File

@ -443,10 +443,9 @@ boost::optional<CScenarioTravel::STravelBonus> CCampaignState::getBonusForCurren
{ {
auto bonuses = getCurrentScenario().travelOptions.bonusesToChoose; auto bonuses = getCurrentScenario().travelOptions.bonusesToChoose;
assert(chosenCampaignBonuses.count(*currentMap) || bonuses.size() == 0); assert(chosenCampaignBonuses.count(*currentMap) || bonuses.size() == 0);
if(bonuses.size())
return bonuses[currentBonusID()]; if(bonuses.empty()) return boost::optional<CScenarioTravel::STravelBonus>();
else else return bonuses[currentBonusID()];
return boost::optional<CScenarioTravel::STravelBonus>();
} }
const CCampaignScenario & CCampaignState::getCurrentScenario() const const CCampaignScenario & CCampaignState::getCurrentScenario() const

View File

@ -83,16 +83,6 @@ public:
class DLL_LINKAGE CCampaignScenario class DLL_LINKAGE CCampaignScenario
{ {
public: public:
std::string mapName; //*.h3m
std::string scenarioName; //from header. human-readble
ui32 packedMapSize; //generally not used
std::set<ui8> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
ui8 regionColor;
ui8 difficulty;
bool conquered;
std::string regionText;
struct DLL_LINKAGE SScenarioPrologEpilog struct DLL_LINKAGE SScenarioPrologEpilog
{ {
bool hasPrologEpilog; bool hasPrologEpilog;
@ -106,17 +96,23 @@ public:
} }
}; };
std::string mapName; //*.h3m
std::string scenarioName; //from header. human-readble
ui32 packedMapSize; //generally not used
std::set<ui8> preconditionRegions; //what we need to conquer to conquer this one (stored as bitfield in h3c)
ui8 regionColor;
ui8 difficulty;
bool conquered;
std::string regionText;
SScenarioPrologEpilog prolog, epilog; SScenarioPrologEpilog prolog, epilog;
CScenarioTravel travelOptions; CScenarioTravel travelOptions;
std::vector<CGHeroInstance *> crossoverHeroes; std::vector<CGHeroInstance *> crossoverHeroes;
const CGHeroInstance * strongestHero(PlayerColor owner) const; const CGHeroInstance * strongestHero(PlayerColor owner) const;
void loadPreconditionRegions(ui32 regions); void loadPreconditionRegions(ui32 regions);
void prepareCrossoverHeroes(std::vector<CGHeroInstance *> heroes); void prepareCrossoverHeroes(std::vector<CGHeroInstance *> heroes);
bool isNotVoid() const; bool isNotVoid() const;
template <typename Handler> void serialize(Handler &h, const int formatVersion) template <typename Handler> void serialize(Handler &h, const int formatVersion)

View File

@ -24,8 +24,6 @@ class CGameHandler;
class CVCMIServer; class CVCMIServer;
class CGameState; class CGameState;
struct StartInfo; struct StartInfo;
class CCPPObjectScript;
class CScriptCallback;
struct BattleResult; struct BattleResult;
struct BattleAttack; struct BattleAttack;
struct BattleStackAttacked; struct BattleStackAttacked;
@ -286,7 +284,6 @@ public:
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ArtifactPosition slot); bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, ArtifactPosition slot);
void spawnWanderingMonsters(CreatureID creatureID); void spawnWanderingMonsters(CreatureID creatureID);
friend class CVCMIServer; friend class CVCMIServer;
friend class CScriptCallback;
private: private:
std::list<PlayerColor> generatePlayerTurnOrder() const; std::list<PlayerColor> generatePlayerTurnOrder() const;