1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-31 22:05:10 +02:00

Implemented deterministic secondary skills, .

This commit is contained in:
DjWarmonger 2013-09-09 15:23:59 +00:00
parent a1d3bcb276
commit 39f9069ed9
6 changed files with 111 additions and 5 deletions

@ -42,6 +42,11 @@ SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possi
return *possibles.begin(); return *possibles.begin();
} }
bool CHeroClass::isMagicHero() const
{
return id % 2; // 0 - might, 1 - magic
}
EAlignment::EAlignment CHeroClass::getAlignment() const EAlignment::EAlignment CHeroClass::getAlignment() const
{ {
return EAlignment::EAlignment(VLC->townh->factions[faction]->alignment); return EAlignment::EAlignment(VLC->townh->factions[faction]->alignment);

@ -116,6 +116,7 @@ public:
std::string imageMapMale; std::string imageMapMale;
std::string imageMapFemale; std::string imageMapFemale;
bool isMagicHero() const;
SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles) const; //picks secondary skill out from given possibilities SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles) const; //picks secondary skill out from given possibilities
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)

@ -986,7 +986,26 @@ const std::string & CGHeroInstance::getBiography() const
return biography; return biography;
return type->biography; return type->biography;
} }
void CGHeroInstance::initObj() //TODO: use bonus system
ui8 CGHeroInstance::maxlevelsToMagicSchool() const
{
return type->heroClass->isMagicHero() ? 3 : 4;
}
ui8 CGHeroInstance::maxlevelsToWisdom() const
{
return type->heroClass->isMagicHero() ? 3 : 6;
}
void CGHeroInstance::SecondarySkillsInfo::resetMagicSchoolCounter()
{
magicSchoolCounter = 1;
}
void CGHeroInstance::SecondarySkillsInfo::resetWisdomCounter()
{
wisdomCounter = 1;
}
void CGHeroInstance::initObj()
{ {
blockVisit = true; blockVisit = true;
auto hs = new HeroSpecial(); auto hs = new HeroSpecial();
@ -996,6 +1015,10 @@ void CGHeroInstance::initObj() //TODO: use bonus system
if(!type) if(!type)
initHero(); //TODO: set up everything for prison before specialties are configured initHero(); //TODO: set up everything for prison before specialties are configured
skillsInfo.randomSeed = rand();
skillsInfo.resetMagicSchoolCounter();
skillsInfo.resetWisdomCounter();
for(const auto &spec : type->spec) //TODO: unfity with bonus system for(const auto &spec : type->spec) //TODO: unfity with bonus system
{ {
auto bonus = new Bonus(); auto bonus = new Bonus();
@ -1636,6 +1659,33 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
{ {
std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible
if (!skillsInfo.magicSchoolCounter)
{
std::vector<SecondarySkill> ss;
ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC, SecondarySkill::EARTH_MAGIC;
auto rng = [=](ui32 val)-> ui32
{
return skillsInfo.randomSeed % val; //must be determined
};
std::random_shuffle(ss.begin(), ss.end(), rng);
for (auto skill : ss)
{
if (cb->isAllowed(2, skill) && !getSecSkillLevel(skill)) //only schools hero doesn't know yet
{
obligatorySkills.push_back(skill);
break; //only one
}
}
}
if (!skillsInfo.wisdomCounter)
{
if (cb->isAllowed(2, SecondarySkill::WISDOM) && !getSecSkillLevel(SecondarySkill::WISDOM))
obligatorySkills.push_back(SecondarySkill::WISDOM);
}
std::vector<SecondarySkill> skills; std::vector<SecondarySkill> skills;
//picking sec. skills for choice //picking sec. skills for choice
std::set<SecondarySkill> basicAndAdv, expert, none; std::set<SecondarySkill> basicAndAdv, expert, none;
@ -1651,9 +1701,19 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
expert.insert(elem.first); expert.insert(elem.first);
none.erase(elem.first); none.erase(elem.first);
} }
for (auto s : obligatorySkills) //don't duplicate them
{
none.erase (s);
basicAndAdv.erase (s);
expert.erase (s);
}
//first offered skill //first offered skill
if(basicAndAdv.size()) if (canLearnSkill() && obligatorySkills.size()) //offer always if possible
{
skills.push_back (obligatorySkills[0]);
}
else if(basicAndAdv.size())
{ {
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv);//upgrade existing SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv);//upgrade existing
skills.push_back(s); skills.push_back(s);
@ -1666,7 +1726,11 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
} }
//second offered skill //second offered skill
if(none.size() && canLearnSkill()) //hero have free skill slot if (canLearnSkill() && obligatorySkills.size() > 1)
{
skills.push_back (obligatorySkills[1]);
}
else if(none.size() && canLearnSkill()) //hero have free skill slot
{ {
skills.push_back(type->heroClass->chooseSecSkill(none)); //new skill skills.push_back(type->heroClass->chooseSecSkill(none)); //new skill
} }

@ -346,6 +346,21 @@ public:
std::vector<HeroSpecial*> specialty; std::vector<HeroSpecial*> specialty;
struct DLL_LINKAGE SecondarySkillsInfo
{
ui32 randomSeed; //skills are determined, initialized at map start
ui8 magicSchoolCounter;
ui8 wisdomCounter;
void resetMagicSchoolCounter();
void resetWisdomCounter();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & randomSeed & magicSchoolCounter & wisdomCounter;
}
} skillsInfo;
//BonusList bonuses; //BonusList bonuses;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -355,7 +370,7 @@ public:
h & static_cast<CArmedInstance&>(*this); h & static_cast<CArmedInstance&>(*this);
h & static_cast<CArtifactSet&>(*this); h & static_cast<CArtifactSet&>(*this);
h & exp & level & name & biography & portrait & mana & secSkills & movement h & exp & level & name & biography & portrait & mana & secSkills & movement
& sex & inTownGarrison & spells & patrol & moveDir; & sex & inTownGarrison & spells & patrol & moveDir & skillsInfo;
h & visitedTown & boat; h & visitedTown & boat;
h & type & specialty & commander; h & type & specialty & commander;
BONUS_TREE_DESERIALIZATION_FIX BONUS_TREE_DESERIALIZATION_FIX
@ -415,6 +430,8 @@ public:
//void giveArtifact (ui32 aid); //void giveArtifact (ui32 aid);
void initHeroDefInfo(); void initHeroDefInfo();
void pushPrimSkill(PrimarySkill::PrimarySkill which, int val); void pushPrimSkill(PrimarySkill::PrimarySkill which, int val);
ui8 maxlevelsToMagicSchool() const;
ui8 maxlevelsToWisdom() const;
void Updatespecialty(); void Updatespecialty();
void updateSkill(SecondarySkill which, int val); void updateSkill(SecondarySkill which, int val);

@ -1010,6 +1010,21 @@ DLL_LINKAGE void HeroLevelUp::applyGs( CGameState *gs )
{ {
CGHeroInstance* h = gs->getHero(hero->id); CGHeroInstance* h = gs->getHero(hero->id);
h->level = level; h->level = level;
//deterministic secondary skills
h->skillsInfo.magicSchoolCounter = (++h->skillsInfo.magicSchoolCounter) % h->maxlevelsToMagicSchool();
h->skillsInfo.wisdomCounter = (++h->skillsInfo.wisdomCounter) % h->maxlevelsToWisdom();
if (vstd::contains(skills, SecondarySkill::WISDOM))
h->skillsInfo.resetWisdomCounter();
SecondarySkill spellSchools[] = {
SecondarySkill::FIRE_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC, SecondarySkill::EARTH_MAGIC};
for (auto skill : spellSchools)
{
if (vstd::contains(skills, SecondarySkill::WISDOM))
{
h->skillsInfo.resetMagicSchoolCounter();
break;
}
}
//specialty //specialty
h->Updatespecialty(); h->Updatespecialty();
} }

@ -205,7 +205,11 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
{ {
sendAndApply(&hlu); sendAndApply(&hlu);
levelUpHero(hero, vstd::pickRandomElementOf (hlu.skills, rand)); auto rng = [&]()-> ui32
{
return hero->skillsInfo.randomSeed; //must be determined
};
levelUpHero(hero, vstd::pickRandomElementOf (hlu.skills, rng));
} }
else if(hlu.skills.size() > 1) else if(hlu.skills.size() > 1)
{ {