mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-31 22:05:10 +02:00
Implemented deterministic secondary skills, #1166.
This commit is contained in:
parent
a1d3bcb276
commit
39f9069ed9
@ -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)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user