mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-19 21:10:12 +02:00
Optimized getHeroStrength method
- replaced 4x access to bonus system with single access - fixed formula for Diplomacy - fxied formula for hero transfer in campaigns - removed pointless sqrt(pow()) construct
This commit is contained in:
parent
5caf12f22f
commit
e035cf9e63
@ -339,7 +339,7 @@ void CampaignState::setCurrentMapAsConquered(std::vector<CGHeroInstance *> heroe
|
|||||||
{
|
{
|
||||||
range::sort(heroes, [](const CGHeroInstance * a, const CGHeroInstance * b)
|
range::sort(heroes, [](const CGHeroInstance * a, const CGHeroInstance * b)
|
||||||
{
|
{
|
||||||
return a->getHeroStrengthForCampaign() > b->getHeroStrengthForCampaign();
|
return a->getValueForCampaign() > b->getValueForCampaign();
|
||||||
});
|
});
|
||||||
|
|
||||||
logGlobal->info("Scenario %d of campaign %s (%s) has been completed", currentMap->getNum(), getFilename(), getNameTranslated());
|
logGlobal->info("Scenario %d of campaign %s (%s) has been completed", currentMap->getNum(), getFilename(), getNameTranslated());
|
||||||
|
@ -97,8 +97,6 @@ const PrimarySkill PrimarySkill::ATTACK(0);
|
|||||||
const PrimarySkill PrimarySkill::DEFENSE(1);
|
const PrimarySkill PrimarySkill::DEFENSE(1);
|
||||||
const PrimarySkill PrimarySkill::SPELL_POWER(2);
|
const PrimarySkill PrimarySkill::SPELL_POWER(2);
|
||||||
const PrimarySkill PrimarySkill::KNOWLEDGE(3);
|
const PrimarySkill PrimarySkill::KNOWLEDGE(3);
|
||||||
const PrimarySkill PrimarySkill::BEGIN(0);
|
|
||||||
const PrimarySkill PrimarySkill::END(4);
|
|
||||||
const PrimarySkill PrimarySkill::EXPERIENCE(4);
|
const PrimarySkill PrimarySkill::EXPERIENCE(4);
|
||||||
|
|
||||||
const BoatId BoatId::NONE(-1);
|
const BoatId BoatId::NONE(-1);
|
||||||
@ -630,6 +628,18 @@ std::string GameResID::entityType()
|
|||||||
return "resource";
|
return "resource";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::array<PrimarySkill, 4> & PrimarySkill::ALL_SKILLS()
|
||||||
|
{
|
||||||
|
static const std::array allSkills = {
|
||||||
|
PrimarySkill(ATTACK),
|
||||||
|
PrimarySkill(DEFENSE),
|
||||||
|
PrimarySkill(SPELL_POWER),
|
||||||
|
PrimarySkill(KNOWLEDGE)
|
||||||
|
};
|
||||||
|
|
||||||
|
return allSkills;
|
||||||
|
}
|
||||||
|
|
||||||
const std::array<GameResID, 7> & GameResID::ALL_RESOURCES()
|
const std::array<GameResID, 7> & GameResID::ALL_RESOURCES()
|
||||||
{
|
{
|
||||||
static const std::array allResources = {
|
static const std::array allResources = {
|
||||||
|
@ -230,8 +230,7 @@ public:
|
|||||||
static const PrimarySkill SPELL_POWER;
|
static const PrimarySkill SPELL_POWER;
|
||||||
static const PrimarySkill KNOWLEDGE;
|
static const PrimarySkill KNOWLEDGE;
|
||||||
|
|
||||||
static const PrimarySkill BEGIN;
|
static const std::array<PrimarySkill, 4> & ALL_SKILLS();
|
||||||
static const PrimarySkill END;
|
|
||||||
|
|
||||||
static const PrimarySkill EXPERIENCE;
|
static const PrimarySkill EXPERIENCE;
|
||||||
|
|
||||||
|
@ -82,13 +82,13 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
|
|||||||
//trimming prim skills
|
//trimming prim skills
|
||||||
for(auto & hero : campaignHeroReplacements)
|
for(auto & hero : campaignHeroReplacements)
|
||||||
{
|
{
|
||||||
for(auto g = PrimarySkill::BEGIN; g < PrimarySkill::END; ++g)
|
for(auto skill : PrimarySkill::ALL_SKILLS())
|
||||||
{
|
{
|
||||||
auto sel = Selector::type()(BonusType::PRIMARY_SKILL)
|
auto sel = Selector::type()(BonusType::PRIMARY_SKILL)
|
||||||
.And(Selector::subtype()(BonusSubtypeID(g)))
|
.And(Selector::subtype()(BonusSubtypeID(skill)))
|
||||||
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
.And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL));
|
||||||
|
|
||||||
hero.hero->getLocalBonus(sel)->val = hero.hero->getHeroClass()->primarySkillInitial[g.getNum()];
|
hero.hero->getLocalBonus(sel)->val = hero.hero->getHeroClass()->primarySkillInitial[skill.getNum()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,14 +337,14 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
|
|||||||
case CampaignBonusType::PRIMARY_SKILL:
|
case CampaignBonusType::PRIMARY_SKILL:
|
||||||
{
|
{
|
||||||
const ui8 * ptr = reinterpret_cast<const ui8 *>(&curBonus->info2);
|
const ui8 * ptr = reinterpret_cast<const ui8 *>(&curBonus->info2);
|
||||||
for(auto g = PrimarySkill::BEGIN; g < PrimarySkill::END; ++g)
|
for(auto skill : PrimarySkill::ALL_SKILLS())
|
||||||
{
|
{
|
||||||
int val = ptr[g.getNum()];
|
int val = ptr[skill.getNum()];
|
||||||
if(val == 0)
|
if(val == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto currentScenario = *gameState->scenarioOps->campState->currentScenario();
|
auto currentScenario = *gameState->scenarioOps->campState->currentScenario();
|
||||||
auto bb = std::make_shared<Bonus>( BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CAMPAIGN_BONUS, val, BonusSourceID(currentScenario), BonusSubtypeID(g) );
|
auto bb = std::make_shared<Bonus>( BonusDuration::PERMANENT, BonusType::PRIMARY_SKILL, BonusSource::CAMPAIGN_BONUS, val, BonusSourceID(currentScenario), BonusSubtypeID(skill) );
|
||||||
hero->addNewBonus(bb);
|
hero->addNewBonus(bb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -551,7 +551,7 @@ void CGameStateCampaign::initHeroes()
|
|||||||
int maxB = -1;
|
int maxB = -1;
|
||||||
for (int b=0; b<heroes.size(); ++b)
|
for (int b=0; b<heroes.size(); ++b)
|
||||||
{
|
{
|
||||||
if (maxB == -1 || heroes[b]->getTotalStrength() > heroes[maxB]->getTotalStrength())
|
if (maxB == -1 || heroes[b]->getValueForCampaign() > heroes[maxB]->getValueForCampaign())
|
||||||
{
|
{
|
||||||
maxB = b;
|
maxB = b;
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ void CGCreature::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
|
|||||||
int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
|
int CGCreature::takenAction(const CGHeroInstance *h, bool allowJoin) const
|
||||||
{
|
{
|
||||||
//calculate relative strength of hero and creatures armies
|
//calculate relative strength of hero and creatures armies
|
||||||
double relStrength = static_cast<double>(h->getTotalStrength()) / getArmyStrength();
|
double relStrength = static_cast<double>(h->getValueForDiplomacy()) / getArmyStrength();
|
||||||
|
|
||||||
int powerFactor;
|
int powerFactor;
|
||||||
if(relStrength >= 7)
|
if(relStrength >= 7)
|
||||||
|
@ -704,19 +704,46 @@ void CGHeroInstance::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
|
|||||||
setStackCount(SlotID(0), identifier.getNum());
|
setStackCount(SlotID(0), identifier.getNum());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<int, 4> CGHeroInstance::getPrimarySkills() const
|
||||||
|
{
|
||||||
|
std::array<int, 4> result;
|
||||||
|
|
||||||
|
auto allSkills = getBonusBearer()->getBonusesOfType(BonusType::PRIMARY_SKILL);
|
||||||
|
for (auto skill : PrimarySkill::ALL_SKILLS())
|
||||||
|
{
|
||||||
|
int ret = allSkills->valOfBonuses(Selector::subtype()(BonusSubtypeID(skill)));
|
||||||
|
int minSkillValue = VLC->engineSettings()->getVectorValue(EGameSettings::HEROES_MINIMAL_PRIMARY_SKILLS, skill.getNum());
|
||||||
|
result[skill] = std::max(ret, minSkillValue); //otherwise, some artifacts may cause negative skill value effect
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
double CGHeroInstance::getFightingStrength() const
|
double CGHeroInstance::getFightingStrength() const
|
||||||
{
|
{
|
||||||
return sqrt((1.0 + 0.05*getPrimSkillLevel(PrimarySkill::ATTACK)) * (1.0 + 0.05*getPrimSkillLevel(PrimarySkill::DEFENSE)));
|
const auto & primarySkills = getPrimarySkills();
|
||||||
|
return getFightingStrengthImpl(primarySkills);
|
||||||
|
}
|
||||||
|
|
||||||
|
double CGHeroInstance::getFightingStrengthImpl(const std::array<int, 4> & primarySkills) const
|
||||||
|
{
|
||||||
|
return sqrt((1.0 + 0.05*primarySkills[PrimarySkill::ATTACK]) * (1.0 + 0.05*primarySkills[PrimarySkill::DEFENSE]));
|
||||||
}
|
}
|
||||||
|
|
||||||
double CGHeroInstance::getMagicStrength() const
|
double CGHeroInstance::getMagicStrength() const
|
||||||
|
{
|
||||||
|
const auto & primarySkills = getPrimarySkills();
|
||||||
|
return getMagicStrengthImpl(primarySkills);
|
||||||
|
}
|
||||||
|
|
||||||
|
double CGHeroInstance::getMagicStrengthImpl(const std::array<int, 4> & primarySkills) const
|
||||||
{
|
{
|
||||||
if (!hasSpellbook())
|
if (!hasSpellbook())
|
||||||
return 1;
|
return 1;
|
||||||
bool atLeastOneCombatSpell = false;
|
bool atLeastOneCombatSpell = false;
|
||||||
for (auto spell : spells)
|
for (auto spell : spells)
|
||||||
{
|
{
|
||||||
if (spellbookContainsSpell(spell) && spell.toSpell()->isCombat())
|
if (spell.toSpell()->isCombat())
|
||||||
{
|
{
|
||||||
atLeastOneCombatSpell = true;
|
atLeastOneCombatSpell = true;
|
||||||
break;
|
break;
|
||||||
@ -724,22 +751,40 @@ double CGHeroInstance::getMagicStrength() const
|
|||||||
}
|
}
|
||||||
if (!atLeastOneCombatSpell)
|
if (!atLeastOneCombatSpell)
|
||||||
return 1;
|
return 1;
|
||||||
return sqrt((1.0 + 0.05*getPrimSkillLevel(PrimarySkill::KNOWLEDGE) * mana / manaLimit()) * (1.0 + 0.05*getPrimSkillLevel(PrimarySkill::SPELL_POWER) * mana / manaLimit()));
|
return sqrt((1.0 + 0.05*primarySkills[PrimarySkill::KNOWLEDGE] * mana / manaLimit()) * (1.0 + 0.05*primarySkills[PrimarySkill::SPELL_POWER] * mana / manaLimit()));
|
||||||
}
|
|
||||||
|
|
||||||
double CGHeroInstance::getMagicStrengthForCampaign() const
|
|
||||||
{
|
|
||||||
return sqrt((1.0 + 0.05 * getPrimSkillLevel(PrimarySkill::KNOWLEDGE)) * (1.0 + 0.05 * getPrimSkillLevel(PrimarySkill::SPELL_POWER)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double CGHeroInstance::getHeroStrength() const
|
double CGHeroInstance::getHeroStrength() const
|
||||||
{
|
{
|
||||||
return sqrt(pow(getFightingStrength(), 2.0) * pow(getMagicStrength(), 2.0));
|
const auto & primarySkills = getPrimarySkills();
|
||||||
|
return getFightingStrengthImpl(primarySkills) * getMagicStrengthImpl(primarySkills);
|
||||||
}
|
}
|
||||||
|
|
||||||
double CGHeroInstance::getHeroStrengthForCampaign() const
|
uint64_t CGHeroInstance::getValueForDiplomacy() const
|
||||||
{
|
{
|
||||||
return sqrt(pow(getFightingStrength(), 2.0) * pow(getMagicStrengthForCampaign(), 2.0));
|
// H3 formula for hero strength when considering diplomacy skill
|
||||||
|
uint64_t armyStrength = getArmyStrength();
|
||||||
|
double heroStrength = sqrt(
|
||||||
|
(1.0 + 0.05 * getPrimSkillLevel(PrimarySkill::ATTACK)) *
|
||||||
|
(1.0 + 0.05 * getPrimSkillLevel(PrimarySkill::DEFENSE))
|
||||||
|
);
|
||||||
|
|
||||||
|
return heroStrength * armyStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CGHeroInstance::getValueForCampaign() const
|
||||||
|
{
|
||||||
|
/// Determined by testing H3: hero is preferred for transfer in campaigns if total sum of his primary skills and his secondary skill levels is greatest
|
||||||
|
uint32_t score = 0;
|
||||||
|
score += getPrimSkillLevel(PrimarySkill::ATTACK);
|
||||||
|
score += getPrimSkillLevel(PrimarySkill::DEFENSE);
|
||||||
|
score += getPrimSkillLevel(PrimarySkill::SPELL_POWER);
|
||||||
|
score += getPrimSkillLevel(PrimarySkill::DEFENSE);
|
||||||
|
|
||||||
|
for (const auto& secondary : secSkills)
|
||||||
|
score += secondary.second;
|
||||||
|
|
||||||
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui64 CGHeroInstance::getTotalStrength() const
|
ui64 CGHeroInstance::getTotalStrength() const
|
||||||
@ -1653,11 +1698,11 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
|||||||
{
|
{
|
||||||
auto primarySkills = handler.enterStruct("primarySkills");
|
auto primarySkills = handler.enterStruct("primarySkills");
|
||||||
|
|
||||||
for(auto i = PrimarySkill::BEGIN; i < PrimarySkill::END; ++i)
|
for(auto skill : PrimarySkill::ALL_SKILLS())
|
||||||
{
|
{
|
||||||
int value = valOfBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(i)).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
int value = valOfBonuses(Selector::typeSubtype(BonusType::PRIMARY_SKILL, BonusSubtypeID(skill)).And(Selector::sourceType()(BonusSource::HERO_BASE_SKILL)));
|
||||||
|
|
||||||
handler.serializeInt(NPrimarySkill::names[i.getNum()], value, 0);
|
handler.serializeInt(NPrimarySkill::names[skill.getNum()], value, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,9 @@ private:
|
|||||||
mutable int lowestCreatureSpeed;
|
mutable int lowestCreatureSpeed;
|
||||||
ui32 movement; //remaining movement points
|
ui32 movement; //remaining movement points
|
||||||
|
|
||||||
|
double getFightingStrengthImpl(const std::array<int, 4> & primarySkills) const;
|
||||||
|
double getMagicStrengthImpl(const std::array<int, 4> & primarySkills) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
@ -201,6 +204,7 @@ public:
|
|||||||
std::vector<SecondarySkill> getLevelUpProposedSecondarySkills(vstd::RNG & rand) const;
|
std::vector<SecondarySkill> getLevelUpProposedSecondarySkills(vstd::RNG & rand) const;
|
||||||
|
|
||||||
ui8 getSecSkillLevel(const SecondarySkill & skill) const; //0 - no skill
|
ui8 getSecSkillLevel(const SecondarySkill & skill) const; //0 - no skill
|
||||||
|
std::array<int, 4> getPrimarySkills() const;
|
||||||
|
|
||||||
/// Returns true if hero has free secondary skill slot.
|
/// Returns true if hero has free secondary skill slot.
|
||||||
bool canLearnSkill() const;
|
bool canLearnSkill() const;
|
||||||
@ -225,9 +229,11 @@ public:
|
|||||||
|
|
||||||
double getFightingStrength() const; // takes attack / defense skill into account
|
double getFightingStrength() const; // takes attack / defense skill into account
|
||||||
double getMagicStrength() const; // takes knowledge / spell power skill but also current mana, whether the hero owns a spell-book and whether that books contains anything into account
|
double getMagicStrength() const; // takes knowledge / spell power skill but also current mana, whether the hero owns a spell-book and whether that books contains anything into account
|
||||||
double getMagicStrengthForCampaign() const; // takes knowledge / spell power skill into account
|
|
||||||
double getHeroStrength() const; // includes fighting and magic strength
|
double getHeroStrength() const; // includes fighting and magic strength
|
||||||
double getHeroStrengthForCampaign() const; // includes fighting and the for-campaign-version of magic strength
|
|
||||||
|
uint32_t getValueForCampaign() const;
|
||||||
|
uint64_t getValueForDiplomacy() const;
|
||||||
|
|
||||||
ui64 getTotalStrength() const; // includes fighting strength and army strength
|
ui64 getTotalStrength() const; // includes fighting strength and army strength
|
||||||
TExpType calculateXp(TExpType exp) const; //apply learning skill
|
TExpType calculateXp(TExpType exp) const; //apply learning skill
|
||||||
int getBasePrimarySkillValue(PrimarySkill which) const; //the value of a base-skill without items or temporary bonuses
|
int getBasePrimarySkillValue(PrimarySkill which) const; //the value of a base-skill without items or temporary bonuses
|
||||||
|
Loading…
x
Reference in New Issue
Block a user