mirror of
https://github.com/vcmi/vcmi.git
synced 2025-02-03 13:01:33 +02:00
Initial experiments on hero & creature casting unification
This commit is contained in:
parent
28087099b8
commit
fb5903d610
@ -2218,7 +2218,7 @@ void CBattleInterface::handleHex(BattleHex myNumber, int eventType)
|
||||
{
|
||||
ui8 skill = 0;
|
||||
if (creatureCasting)
|
||||
skill = sactive->valOfBonuses(Selector::typeSubtype(Bonus::SPELLCASTER, SpellID::TELEPORT));
|
||||
skill = sactive->getSpellSchoolLevel(SpellID(SpellID::TELEPORT).toSpell());
|
||||
else
|
||||
skill = getActiveHero()->getSpellSchoolLevel (CGI->spellh->objects[spellToCast->additionalInfo]);
|
||||
//TODO: explicitely save power, skill
|
||||
|
@ -1152,6 +1152,21 @@ bool CStack::canBeHealed() const
|
||||
&& !hasBonusOfType(Bonus::SIEGE_WEAPON);
|
||||
}
|
||||
|
||||
ui8 CStack::getSpellSchoolLevel(const CSpell * spell, int * outSelectedSchool) const
|
||||
{
|
||||
int skill = valOfBonuses(Selector::typeSubtype(Bonus::SPELLCASTER, spell->id));
|
||||
|
||||
vstd::abetween(skill, 0, 3);
|
||||
|
||||
return skill;
|
||||
}
|
||||
|
||||
ui32 CStack::getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const
|
||||
{
|
||||
//stacks does not have spellpower etc. (yet?)
|
||||
return base;
|
||||
}
|
||||
|
||||
bool CMP_stack::operator()( const CStack* a, const CStack* b )
|
||||
{
|
||||
switch(phase)
|
||||
|
@ -1,5 +1,14 @@
|
||||
#pragma once
|
||||
/*
|
||||
* BattleState.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BattleHex.h"
|
||||
#include "HeroBonus.h"
|
||||
@ -12,16 +21,7 @@
|
||||
#include "GameConstants.h"
|
||||
#include "CBattleCallback.h"
|
||||
#include "int3.h"
|
||||
|
||||
/*
|
||||
* BattleState.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "spells/Magic.h"
|
||||
|
||||
class CGHeroInstance;
|
||||
class CStack;
|
||||
@ -159,7 +159,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
static int battlefieldTypeToTerrain(int bfieldType); //converts above to ERM BI format
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor
|
||||
class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor, public ISpellCaster
|
||||
{
|
||||
public:
|
||||
const CStackInstance *base; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc)
|
||||
@ -222,6 +222,10 @@ public:
|
||||
std::pair<int,int> countKilledByAttack(int damageReceived) const; //returns pair<killed count, new left HP>
|
||||
void prepareAttacked(BattleStackAttacked &bsa, CRandomGenerator & rand, boost::optional<int> customCount = boost::none) const; //requires bsa.damageAmout filled
|
||||
|
||||
///ISpellCaster
|
||||
ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const override;
|
||||
ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
assert(isIndependentNode());
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "../IGameCallback.h"
|
||||
#include "../CGameState.h"
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../BattleState.h"
|
||||
|
||||
///helpers
|
||||
static void showInfoDialog(const PlayerColor playerID, const ui32 txtID, const ui16 soundID)
|
||||
@ -883,6 +884,26 @@ ui8 CGHeroInstance::getSpellSchoolLevel(const CSpell * spell, int *outSelectedSc
|
||||
return skill;
|
||||
}
|
||||
|
||||
ui32 CGHeroInstance::getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const
|
||||
{
|
||||
//applying sorcery secondary skill
|
||||
|
||||
base *= (100.0 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SORCERY)) / 100.0;
|
||||
base *= (100.0 + valOfBonuses(Bonus::SPELL_DAMAGE) + valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, spell->id.toEnum())) / 100.0;
|
||||
|
||||
spell->forEachSchool([&base, this](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
base *= (100.0 + valOfBonuses(cnf.damagePremyBonus)) / 100.0;
|
||||
stop = true; //only bonus from one school is used
|
||||
});
|
||||
|
||||
if (affectedStack && affectedStack->getCreature()->level) //Hero specials like Solmyr, Deemer
|
||||
base *= (100. + ((valOfBonuses(Bonus::SPECIAL_SPELL_LEV, spell->id.toEnum()) * level) / affectedStack->getCreature()->level)) / 100.0;
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
|
||||
{
|
||||
return spell->isCastableBy(this, nullptr !=getArt(ArtifactPosition::SPELLBOOK), spells);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "CObjectHandler.h"
|
||||
#include "CArmedInstance.h"
|
||||
#include "../spells/Magic.h"
|
||||
|
||||
#include "../CArtHandler.h" // For CArtifactSet
|
||||
#include "../CRandomGenerator.h"
|
||||
@ -35,7 +36,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet
|
||||
class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public ISpellCaster
|
||||
{
|
||||
public:
|
||||
enum ECanDig
|
||||
@ -162,14 +163,13 @@ public:
|
||||
int maxMovePoints(bool onLand) const;
|
||||
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
|
||||
|
||||
//int getSpellSecLevel(int spell) const; //returns level of secondary ability (fire, water, earth, air magic) known to this hero and applicable to given spell; -1 if error
|
||||
static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
|
||||
double getFightingStrength() const; // takes attack / defense skill into account
|
||||
double getMagicStrength() const; // takes knowledge / spell power skill into account
|
||||
double getHeroStrength() const; // includes fighting and magic strength
|
||||
ui64 getTotalStrength() const; // includes fighting strength and army strength
|
||||
TExpType calculateXp(TExpType exp) const; //apply learning skill
|
||||
ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const; //returns level on which given spell would be cast by this hero (0 - none, 1 - basic etc); optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
|
||||
|
||||
bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
|
||||
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
|
||||
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
|
||||
@ -198,13 +198,18 @@ public:
|
||||
|
||||
CGHeroInstance();
|
||||
virtual ~CGHeroInstance();
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
///ArtBearer
|
||||
ArtBearer::ArtBearer bearerType() const override;
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///IBonusBearer
|
||||
CBonusSystemNode *whereShouldBeAttached(CGameState *gs) override;
|
||||
std::string nodeName() const override;
|
||||
|
||||
///ISpellCaster
|
||||
ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const override;
|
||||
ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const override;
|
||||
|
||||
void deserializationFix();
|
||||
|
||||
void initObj() override;
|
||||
|
@ -310,8 +310,8 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const C
|
||||
//TODO: what with other creatures casting hypnotize, Faerie Dragons style?
|
||||
ui64 subjectHealth = (obj->count - 1) * obj->MaxHealth() + obj->firstHPleft;
|
||||
//apply 'damage' bonus for hypnotize, including hero specialty
|
||||
ui64 maxHealth = owner->calculateBonus(caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
|
||||
* owner->power + owner->getPower(caster->getSpellSchoolLevel(owner)), caster, obj);
|
||||
ui64 maxHealth = caster->getSpellBonus(owner, caster->getPrimSkillLevel(PrimarySkill::SPELL_POWER)
|
||||
* owner->power + owner->getPower(caster->getSpellSchoolLevel(owner)), obj);
|
||||
if (subjectHealth > maxHealth)
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ ui32 DefaultSpellMechanics::calculateHealedHP(const CGHeroInstance* caster, cons
|
||||
healedHealth = (spellPowerSkill + sacrificedStack->MaxHealth() + levelPower) * sacrificedStack->count;
|
||||
else
|
||||
healedHealth = spellPowerSkill * owner->power + levelPower; //???
|
||||
healedHealth = owner->calculateBonus(healedHealth, caster, stack);
|
||||
healedHealth = caster->getSpellBonus(owner, healedHealth, stack);
|
||||
return std::min<ui32>(healedHealth, stack->MaxHealth() - stack->firstHPleft + (owner->isRisingSpell() ? stack->baseAmount * stack->MaxHealth() : 0));
|
||||
}
|
||||
|
||||
|
@ -169,29 +169,7 @@ const CSpell::LevelInfo & CSpell::getLevelInfo(const int level) const
|
||||
return levels.at(level);
|
||||
}
|
||||
|
||||
ui32 CSpell::calculateBonus(ui32 baseDamage, const CGHeroInstance * caster, const CStack * affectedCreature) const
|
||||
{
|
||||
ui32 ret = baseDamage;
|
||||
|
||||
//applying sorcery secondary skill
|
||||
if(caster)
|
||||
{
|
||||
ret *= (100.0 + caster->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::SORCERY)) / 100.0;
|
||||
ret *= (100.0 + caster->valOfBonuses(Bonus::SPELL_DAMAGE) + caster->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, id.toEnum())) / 100.0;
|
||||
|
||||
forEachSchool([&](const SpellSchoolInfo & cnf, bool & stop)
|
||||
{
|
||||
ret *= (100.0 + caster->valOfBonuses(cnf.damagePremyBonus)) / 100.0;
|
||||
stop = true; //only bonus from one school is used
|
||||
});
|
||||
|
||||
if (affectedCreature && affectedCreature->getCreature()->level) //Hero specials like Solmyr, Deemer
|
||||
ret *= (100. + ((caster->valOfBonuses(Bonus::SPECIAL_SPELL_LEV, id.toEnum()) * caster->level) / affectedCreature->getCreature()->level)) / 100.0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const
|
||||
ui32 CSpell::calculateDamage(const ISpellCaster * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const
|
||||
{
|
||||
ui32 ret = 0; //value to return
|
||||
|
||||
@ -230,7 +208,9 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
|
||||
ret /= 100;
|
||||
}
|
||||
}
|
||||
ret = calculateBonus(ret, caster, affectedCreature);
|
||||
|
||||
if(nullptr != caster) //todo: make sure that caster always present
|
||||
ret = caster->getSpellBonus(this, ret, affectedCreature);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Magic.h"
|
||||
#include "../IHandlerBase.h"
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../int3.h"
|
||||
@ -248,11 +248,8 @@ public:
|
||||
//internal, for use only by Mechanics classes
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) const;
|
||||
|
||||
//internal, for use only by Mechanics classes. applying secondary skills
|
||||
ui32 calculateBonus(ui32 baseDamage, const CGHeroInstance * caster, const CStack * affectedCreature) const;
|
||||
|
||||
///calculate spell damage on stack taking caster`s secondary skills and affectedCreature`s bonuses into account
|
||||
ui32 calculateDamage(const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const;
|
||||
ui32 calculateDamage(const ISpellCaster * caster, const CStack * affectedCreature, int spellSchoolLevel, int usedSpellPower) const;
|
||||
|
||||
///selects from allStacks actually affected stacks
|
||||
std::set<const CStack *> getAffectedStacks(const CBattleInfoCallback * cb, ECastingMode::ECastingMode mode, PlayerColor casterColor, int spellLvl, BattleHex destination, const CGHeroInstance * caster = nullptr) const;
|
||||
|
32
lib/spells/Magic.h
Normal file
32
lib/spells/Magic.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Magic.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* High-level interface for spells subsystem
|
||||
*/
|
||||
|
||||
|
||||
class CSpell;
|
||||
class CStack;
|
||||
|
||||
class DLL_LINKAGE ISpellCaster
|
||||
{
|
||||
public:
|
||||
virtual ~ISpellCaster(){};
|
||||
|
||||
/// returns level on which given spell would be cast by this(0 - none, 1 - basic etc);
|
||||
/// caster may not know this spell at all
|
||||
/// optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic
|
||||
virtual ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const = 0;
|
||||
|
||||
virtual ui32 getSpellBonus(const CSpell * spell, ui32 base, const CStack * affectedStack) const = 0;
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user