mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Moved battle effects to bonus system. May be buggy.
Moved creature damage to bonus system, simplified its handling. Some changes and tweaks. Support for Adela's bless.
This commit is contained in:
parent
34b4e09927
commit
bfe266a377
@ -3010,16 +3010,17 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
|
||||
|
||||
//blitting amoutn background box
|
||||
SDL_Surface *amountBG = NULL;
|
||||
if(curStack.effects.size() == 0)
|
||||
if(!curStack.bonuses.size())
|
||||
{
|
||||
amountBG = amountNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
int pos=0; //determining total positiveness of effects
|
||||
for(int c=0; c<curStack.effects.size(); ++c)
|
||||
for(BonusList::const_iterator it = curStack.bonuses.begin(); it != curStack.bonuses.end(); it++)
|
||||
{
|
||||
pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
|
||||
if (it->source == Bonus::CASTED_SPELL)
|
||||
pos += CGI->spellh->spells[ it->id ].positiveness;
|
||||
}
|
||||
if(pos > 0)
|
||||
{
|
||||
|
@ -2148,12 +2148,15 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
|
||||
{
|
||||
//spell effects
|
||||
int printed=0; //how many effect pics have been printed
|
||||
BOOST_FOREACH(const CStack::StackEffect &effect, battleStack->effects)
|
||||
BOOST_FOREACH(const Bonus effect, battleStack->bonuses)
|
||||
{
|
||||
blitAt(graphics->spellEffectsPics->ourImages[effect.id + 1].bitmap, 127 + 52 * printed, 186, *bitmap);
|
||||
++printed;
|
||||
if(printed >= 3) //we can fit only 3 effects
|
||||
break;
|
||||
if (effect.source == Bonus::CASTED_SPELL)
|
||||
{
|
||||
blitAt(graphics->spellEffectsPics->ourImages[effect.id + 1].bitmap, 127 + 52 * printed, 186, *bitmap);
|
||||
++printed;
|
||||
if(printed >= 3) //we can fit only 3 effects
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//print current health
|
||||
|
@ -574,7 +574,7 @@ void SetStackEffect::applyCl( CClient *cl )
|
||||
BattleSpellCast sc;
|
||||
sc.id = effect.id;
|
||||
sc.side = 3; //doesn't matter
|
||||
sc.skill = effect.level;
|
||||
sc.skill = effect.val;
|
||||
|
||||
//informing about effects
|
||||
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
|
||||
|
@ -8,7 +8,7 @@
|
||||
6 1 0 0 146
|
||||
7 1 0 0 10
|
||||
8 2 5 27 0
|
||||
9 6 41 0 3
|
||||
9 6 3 41 0
|
||||
10 8 45 0 0
|
||||
11 3 3 20 0
|
||||
12 1 0 0 8
|
||||
@ -28,7 +28,7 @@
|
||||
26 2 5 24 0
|
||||
27 2 5 27 0
|
||||
28 2 5 11 0
|
||||
29 7 51 0 0
|
||||
29 7 0 51 0
|
||||
30 3 3 16 0
|
||||
31 1 0 0 20
|
||||
32 1 0 0 30
|
||||
@ -42,7 +42,7 @@
|
||||
40 3 3 60 0
|
||||
41 2 5 8 1
|
||||
42 2 5 11 0
|
||||
43 7 51 0 0
|
||||
43 7 0 51 0
|
||||
44 1 0 0 34
|
||||
45 3 3 19 0
|
||||
46 8 53 0 0
|
||||
|
@ -124,16 +124,6 @@ CCreature::CCreature()
|
||||
doubleWide = false;
|
||||
nodeType = CBonusSystemNode::CREATURE;
|
||||
}
|
||||
|
||||
ui32 CCreature::getMinDamage() const
|
||||
{
|
||||
return damageMin + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 1);
|
||||
}
|
||||
ui32 CCreature::getMaxDamage() const
|
||||
{
|
||||
return damageMax + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 2);
|
||||
}
|
||||
|
||||
void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
|
||||
{
|
||||
Bonus added(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER);
|
||||
@ -272,8 +262,10 @@ void CCreatureHandler::loadCreatures()
|
||||
ncre.addBonus(ncre.attack, Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
|
||||
ncre.defence = readNumber(befi, i, andame, buf);
|
||||
ncre.addBonus(ncre.defence, Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
|
||||
ncre.damageMin = readNumber(befi, i, andame, buf);
|
||||
ncre.damageMin = readNumber(befi, i, andame, buf); //not used anymore?
|
||||
ncre.addBonus(ncre.damageMin, Bonus::CREATURE_DAMAGE, 1);
|
||||
ncre.damageMax = readNumber(befi, i, andame, buf);
|
||||
ncre.addBonus(ncre.damageMax, Bonus::CREATURE_DAMAGE, 2);
|
||||
|
||||
ncre.shots = readNumber(befi, i, andame, buf);
|
||||
ncre.spells = readNumber(befi, i, andame, buf);
|
||||
|
@ -60,8 +60,6 @@ public:
|
||||
si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought
|
||||
static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
|
||||
bool isMyUpgrade(const CCreature *anotherCre) const;
|
||||
ui32 getMinDamage() const;
|
||||
ui32 getMaxDamage() const;
|
||||
|
||||
void addBonus(int val, int type, int subtype = -1);
|
||||
void getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const;
|
||||
|
@ -1091,6 +1091,7 @@ void CGHeroInstance::initObj()
|
||||
break;
|
||||
case 6://damage bonus for bless (Adela)
|
||||
bonus.type = Bonus::SPECIAL_BLESS_DAMAGE;
|
||||
bonus.subtype = it->subtype; //spell id if you ever wanted to use it otherwise
|
||||
bonus.additionalInfo = it->additionalinfo; //damage factor
|
||||
speciality.bonuses.push_back (bonus);
|
||||
break;
|
||||
|
@ -278,15 +278,6 @@ void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*=
|
||||
out.insert(&IObjectInterface::cb->gameState()->globalEffects);
|
||||
}
|
||||
|
||||
ui32 CStackInstance::getMinDamage() const
|
||||
{
|
||||
return type->damageMin + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 1);
|
||||
}
|
||||
ui32 CStackInstance::getMaxDamage() const
|
||||
{
|
||||
return type->damageMax + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 2);
|
||||
}
|
||||
|
||||
std::string CStackInstance::getQuantityTXT(bool capitalized /*= true*/) const
|
||||
{
|
||||
return VLC->generaltexth->arraytxt[174 + getQuantityID()*3 + 2 - capitalized];
|
||||
|
@ -25,8 +25,6 @@ public:
|
||||
const CArmedInstance *armyObj; //stack must be part of some army, army must be part of some object
|
||||
const CCreature *type;
|
||||
TQuantity count;
|
||||
ui32 getMinDamage() const;
|
||||
ui32 getMaxDamage() const;
|
||||
ui32 experience; //TODO: handle
|
||||
//TODO: stack artifacts
|
||||
|
||||
|
@ -742,20 +742,161 @@ ui32 CStack::Speed( int turn /*= 0*/ ) const
|
||||
return speed;
|
||||
}
|
||||
|
||||
const CStack::StackEffect * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
|
||||
const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
|
||||
{
|
||||
for (unsigned int i=0; i< effects.size(); i++)
|
||||
if(effects[i].id == id)
|
||||
if(!turn || effects[i].turnsRemain > turn)
|
||||
return &effects[i];
|
||||
for (BonusList::const_iterator it = bonuses.begin(); it != bonuses.end(); it++)
|
||||
{
|
||||
if(it->id == id)
|
||||
{
|
||||
if(!turn || it->turnsRemain > turn)
|
||||
return &(*it);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CStack::stackEffectToFeature(BonusList & sf, const Bonus & sse)
|
||||
{
|
||||
si32 power = VLC->spellh->spells[sse.id].powers[sse.val];
|
||||
switch(sse.id)
|
||||
{
|
||||
case 27: //shield
|
||||
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 28: //air shield
|
||||
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 29: //fire shield
|
||||
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 30: //protection from air
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 31: //protection from fire
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 32: //protection from water
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 33: //protection from earth
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 34: //anti-magic
|
||||
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 41: //bless
|
||||
if (hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, 41)) //TODO: better handling of bonus percentages
|
||||
{
|
||||
int damagePercent = dynamic_cast<const CGHeroInstance*>(armyObj)->level * valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / type->level;
|
||||
sf.push_back(featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.back().valType = Bonus::PERCENT_TO_ALL;
|
||||
}
|
||||
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 42: //curse
|
||||
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 43: //bloodlust
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 44: //precision
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 45: //weakness
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 46: //stone skin
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 47: //disrupting ray
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 48: //prayer
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 49: //mirth
|
||||
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 50: //sorrow
|
||||
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 51: //fortune
|
||||
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 52: //misfortune
|
||||
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 53: //haste
|
||||
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 54: //slow
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 55: //slayer
|
||||
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 56: //frenzy
|
||||
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56].powers[sse.val]/100.0, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 58: //counterstrike
|
||||
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 59: //bersek
|
||||
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 60: //hypnotize
|
||||
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 61: //forgetfulness
|
||||
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 62: //blind
|
||||
sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ui8 CStack::howManyEffectsSet(ui16 id) const
|
||||
{
|
||||
ui8 ret = 0;
|
||||
for (unsigned int i=0; i< effects.size(); i++)
|
||||
if(effects[i].id == id) //effect found
|
||||
for (BonusList::const_iterator it = bonuses.begin(); it != bonuses.end(); it++)
|
||||
if(it->id == id) //effect found
|
||||
{
|
||||
++ret;
|
||||
}
|
||||
@ -2941,7 +3082,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
|
||||
if(attacker->getEffect(55)) //slayer handling
|
||||
{
|
||||
std::vector<int> affectedIds;
|
||||
int spLevel = attacker->getEffect(55)->level;
|
||||
int spLevel = attacker->getEffect(55)->val;
|
||||
|
||||
for(int g = 0; g < VLC->creh->creatures.size(); ++g)
|
||||
{
|
||||
@ -2961,7 +3102,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
|
||||
{
|
||||
if(defender->type->idNumber == affectedIds[g])
|
||||
{
|
||||
attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->level];
|
||||
attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->val];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3038,7 +3179,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
|
||||
}
|
||||
if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
|
||||
{
|
||||
multBonus *= 0.8f * float(VLC->spellh->spells[42].powers[attacker->getEffect(42)->level]); //the second factor is 1 or 0
|
||||
multBonus *= 0.8f * float(VLC->spellh->spells[42].powers[attacker->getEffect(42)->val]); //the second factor is 1 or 0
|
||||
}
|
||||
|
||||
class HLP
|
||||
@ -3046,9 +3187,9 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
|
||||
public:
|
||||
static bool hasAdvancedAirShield(const CStack * stack)
|
||||
{
|
||||
for(int g=0; g<stack->effects.size(); ++g)
|
||||
for (BonusList::const_iterator it = stack->bonuses.begin(); it != stack->bonuses.end(); it++)
|
||||
{
|
||||
if (stack->effects[g].id == 28 && stack->effects[g].level >= 2)
|
||||
if (it->id == 28 && it->val >= 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -3077,12 +3218,12 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
|
||||
|
||||
if(attacker->getEffect(42)) //curse handling (rest)
|
||||
{
|
||||
minDmg -= VLC->spellh->spells[42].powers[attacker->getEffect(42)->level];
|
||||
minDmg -= VLC->spellh->spells[42].powers[attacker->getEffect(42)->val];
|
||||
returnedVal = std::make_pair(int(minDmg), int(minDmg));
|
||||
}
|
||||
else if(attacker->getEffect(41)) //bless handling
|
||||
{
|
||||
maxDmg += VLC->spellh->spells[41].powers[attacker->getEffect(41)->level];
|
||||
maxDmg += VLC->spellh->spells[41].powers[attacker->getEffect(41)->val];
|
||||
returnedVal = std::make_pair(int(maxDmg), int(maxDmg));
|
||||
}
|
||||
else
|
||||
|
@ -261,29 +261,34 @@ public:
|
||||
si16 shots; //how many shots left
|
||||
|
||||
std::set<ECombatInfo> state;
|
||||
struct StackEffect
|
||||
{
|
||||
ui16 id; //spell id
|
||||
ui8 level; //skill level
|
||||
si16 turnsRemain;
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & id & level & turnsRemain;
|
||||
}
|
||||
};
|
||||
std::vector<StackEffect> effects;
|
||||
|
||||
//overrides
|
||||
const CCreature* getCreature() const {return type;}
|
||||
|
||||
CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor
|
||||
CStack() : ID(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor
|
||||
const StackEffect * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
|
||||
const Bonus * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
|
||||
ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack
|
||||
bool willMove(int turn = 0) const; //if stack has remaining move this turn
|
||||
bool moved(int turn = 0) const; //if stack was already moved this turn
|
||||
bool canMove(int turn = 0) const; //if stack can move
|
||||
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
|
||||
void stackEffectToFeature(BonusList & sf, const Bonus & sse);
|
||||
|
||||
static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
|
||||
{
|
||||
Bonus hb(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo));
|
||||
hb.effectRange = limit;
|
||||
hb.source = Bonus::SPELL; //right?
|
||||
return hb;
|
||||
}
|
||||
|
||||
static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
|
||||
{
|
||||
Bonus ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
|
||||
ret.valType = valType;
|
||||
ret.source = Bonus::SPELL; //right?
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool doubleWide() const;
|
||||
int occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
|
||||
|
@ -98,6 +98,14 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector,
|
||||
if(selector(*i) && (!limit || limit(*i)))
|
||||
out.push_back(*i);
|
||||
}
|
||||
void DLL_EXPORT BonusList::removeSpells(Bonus::BonusSource sourceType)
|
||||
{
|
||||
for(iterator i = begin(); i != end(); i++)
|
||||
{
|
||||
if (i->source == sourceType)
|
||||
erase(i);
|
||||
}
|
||||
}
|
||||
|
||||
void BonusList::limit(const CBonusSystemNode &node)
|
||||
{
|
||||
@ -294,6 +302,15 @@ ui16 CBonusSystemNode::MaxHealth() const
|
||||
return valOfBonuses(Bonus::STACK_HEALTH);
|
||||
}
|
||||
|
||||
ui32 CBonusSystemNode::getMinDamage() const
|
||||
{
|
||||
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 1));
|
||||
}
|
||||
ui32 CBonusSystemNode::getMaxDamage() const
|
||||
{
|
||||
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 2));
|
||||
}
|
||||
|
||||
CBonusSystemNode::CBonusSystemNode()
|
||||
{
|
||||
nodeType = UNKNOWN;
|
||||
@ -395,6 +412,10 @@ CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second)
|
||||
{
|
||||
return CSelectorsConjunction(first, second);
|
||||
}
|
||||
CSelector DLL_EXPORT operator||(const CSelector &first, const CSelector &second)
|
||||
{
|
||||
return CSelectorsAlternative(first, second);
|
||||
}
|
||||
|
||||
namespace Selector
|
||||
{
|
||||
|
@ -302,6 +302,7 @@ public:
|
||||
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *source = NULL) const;
|
||||
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *source = NULL) const;
|
||||
void DLL_EXPORT getModifiersWDescr(TModDescr &out) const;
|
||||
void DLL_EXPORT removeSpells(Bonus::BonusSource sourceType);
|
||||
|
||||
//special find functions
|
||||
DLL_EXPORT Bonus * getFirst(const CSelector &select);
|
||||
@ -359,8 +360,8 @@ public:
|
||||
bool hasBonusFrom(ui8 source, ui32 sourceID) const;
|
||||
void getModifiersWDescr( TModDescr &out, Bonus::BonusType type, int subtype = -1 ) const; //out: pairs<modifier value, modifier description>
|
||||
int getBonusesCount(int from, int id) const;
|
||||
virtual ui32 getMinDamage() const {return 0;}; //used for stacks and creatures only
|
||||
virtual ui32 getMaxDamage() const {return 0;};
|
||||
virtual ui32 getMinDamage() const; //used for stacks and creatures only
|
||||
virtual ui32 getMaxDamage() const;
|
||||
|
||||
int MoraleVal() const; //range [-3, +3]
|
||||
int LuckVal() const; //range [-3, +3]
|
||||
@ -424,6 +425,20 @@ public:
|
||||
};
|
||||
CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second);
|
||||
|
||||
class DLL_EXPORT CSelectorsAlternative
|
||||
{
|
||||
const CSelector first, second;
|
||||
public:
|
||||
CSelectorsAlternative(const CSelector &First, const CSelector &Second)
|
||||
:first(First), second(Second)
|
||||
{
|
||||
}
|
||||
bool operator()(const Bonus &bonus) const
|
||||
{
|
||||
return first(bonus) || second(bonus);
|
||||
}
|
||||
};
|
||||
CSelector DLL_EXPORT operator||(const CSelector &first, const CSelector &second);
|
||||
|
||||
template<typename T>
|
||||
class CSelectFieldEqual
|
||||
|
@ -1123,7 +1123,7 @@ struct SetStackEffect : public CPackForClient //3010
|
||||
void applyCl(CClient *cl);
|
||||
|
||||
std::vector<ui32> stacks; //affected stacks (IDs)
|
||||
CStack::StackEffect effect; //type of effect
|
||||
Bonus effect; //type of effect
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & stacks & effect;
|
||||
|
@ -760,13 +760,13 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
|
||||
s->firstHPleft = s->MaxHealth();
|
||||
|
||||
//remove effects and restore only those with remaining turns in duration
|
||||
std::vector<CStack::StackEffect> tmpEffects = s->effects;
|
||||
s->effects.clear();
|
||||
for(int i=0; i < tmpEffects.size(); i++)
|
||||
BonusList tmpEffects = s->bonuses;
|
||||
s->bonuses.removeSpells(Bonus::CASTED_SPELL);
|
||||
for (BonusList::iterator it = tmpEffects.begin(); it != tmpEffects.end(); it++)
|
||||
{
|
||||
tmpEffects[i].turnsRemain--;
|
||||
if(tmpEffects[i].turnsRemain > 0)
|
||||
s->effects.push_back(tmpEffects[i]);
|
||||
it->turnsRemain--;
|
||||
if(it->turnsRemain > 0)
|
||||
s->bonuses.push_back(*it);
|
||||
}
|
||||
|
||||
//the same as above for features
|
||||
@ -929,17 +929,17 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
|
||||
CStack *s = gs->curB->getStack(*it);
|
||||
if(s && !vstd::contains(resisted, s->ID)) //if stack exists and it didn't resist
|
||||
{
|
||||
std::vector<CStack::StackEffect> remainingEff;
|
||||
for(int g=0; g< s->effects.size(); ++g)
|
||||
BonusList remainingEff;
|
||||
for (BonusList::iterator it = remainingEff.begin(); it != remainingEff.end(); it++)
|
||||
{
|
||||
if (onlyHelpful && VLC->spellh->spells[ s->effects[g].id ].positiveness != 1)
|
||||
if (onlyHelpful && VLC->spellh->spells[ it->id ].positiveness != 1)
|
||||
{
|
||||
remainingEff.push_back(s->effects[g]);
|
||||
remainingEff.push_back(*it);
|
||||
}
|
||||
|
||||
}
|
||||
s->effects.clear(); //removing all effects
|
||||
s->effects = remainingEff; //assigning effects that should remain
|
||||
s->bonuses.removeSpells(Bonus::CASTED_SPELL); //removing all effects
|
||||
s->bonuses = remainingEff; //assigning effects that should remain
|
||||
|
||||
//removing all features from spells
|
||||
BonusList tmpFeatures = s->bonuses;
|
||||
@ -1000,169 +1000,23 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
|
||||
}
|
||||
}
|
||||
|
||||
static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
|
||||
{
|
||||
Bonus hb(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo));
|
||||
hb.effectRange = limit;
|
||||
return hb;
|
||||
}
|
||||
|
||||
static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType)
|
||||
{
|
||||
Bonus ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
|
||||
ret.valType = valType;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BonusList stackEffectToFeature(const CStack::StackEffect & sse)
|
||||
{
|
||||
BonusList sf;
|
||||
si32 power = VLC->spellh->spells[sse.id].powers[sse.level];
|
||||
switch(sse.id)
|
||||
{
|
||||
case 27: //shield
|
||||
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 28: //air shield
|
||||
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 29: //fire shield
|
||||
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 30: //protection from air
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 31: //protection from fire
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 32: //protection from water
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 33: //protection from earth
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 34: //anti-magic
|
||||
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 41: //bless
|
||||
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 42: //curse
|
||||
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.level >= 2 ? 20 : 0));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 43: //bloodlust
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 44: //precision
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 45: //weakness
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 46: //stone skin
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 47: //disrupting ray
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 48: //prayer
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 49: //mirth
|
||||
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 50: //sorrow
|
||||
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 51: //fortune
|
||||
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 52: //misfortune
|
||||
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 53: //haste
|
||||
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 54: //slow
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 55: //slayer
|
||||
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.level, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 56: //frenzy
|
||||
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56].powers[sse.level]/100.0, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 58: //counterstrike
|
||||
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 59: //bersek
|
||||
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.level, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 60: //hypnotize
|
||||
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.level, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 61: //forgetfulness
|
||||
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.level, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
case 62: //blind
|
||||
sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().id = sse.id;
|
||||
break;
|
||||
}
|
||||
|
||||
return sf;
|
||||
}
|
||||
|
||||
void actualizeEffect(CStack * s, CStack::StackEffect & ef)
|
||||
void actualizeEffect(CStack * s, Bonus & ef)
|
||||
{
|
||||
//actualizing effects vector
|
||||
for(int g=0; g<s->effects.size(); ++g)
|
||||
for (BonusList::iterator it = s->bonuses.begin(); it != s->bonuses.end(); it++)
|
||||
{
|
||||
if(s->effects[g].id == ef.id)
|
||||
if(it->id == ef.id)
|
||||
{
|
||||
s->effects[g].turnsRemain = std::max(s->effects[g].turnsRemain, ef.turnsRemain);
|
||||
it->turnsRemain = std::max(it->turnsRemain, ef.turnsRemain);
|
||||
}
|
||||
}
|
||||
//actualizing features vector
|
||||
BonusList sf = stackEffectToFeature(ef);
|
||||
BonusList sf;
|
||||
s->stackEffectToFeature(sf, ef);
|
||||
|
||||
BOOST_FOREACH(const Bonus &fromEffect, sf)
|
||||
{
|
||||
BOOST_FOREACH(Bonus &stackBonus, s->bonuses)
|
||||
BOOST_FOREACH(Bonus &stackBonus, s->bonuses) //TODO: optimize
|
||||
{
|
||||
if(stackBonus.source == Bonus::SPELL_EFFECT && stackBonus.type == fromEffect.type && stackBonus.subtype == fromEffect.subtype)
|
||||
{
|
||||
@ -1173,16 +1027,6 @@ void actualizeEffect(CStack * s, CStack::StackEffect & ef)
|
||||
|
||||
}
|
||||
|
||||
bool containsEff(const std::vector<CStack::StackEffect> & vec, int effectId)
|
||||
{
|
||||
for(int g=0; g<vec.size(); ++g)
|
||||
{
|
||||
if(vec[g].id == effectId)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
|
||||
{
|
||||
BOOST_FOREACH(ui32 id, stacks)
|
||||
@ -1190,10 +1034,11 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
|
||||
CStack *s = gs->curB->getStack(id);
|
||||
if(s)
|
||||
{
|
||||
if(effect.id == 42 || !containsEff(s->effects, effect.id))//disrupting ray or not on the list - just add
|
||||
if(effect.id == 42 || !s->hasBonus(Selector::source(Bonus::CASTED_SPELL, effect.id)))//disrupting ray or not on the list - just add
|
||||
{
|
||||
s->effects.push_back(effect);
|
||||
BonusList sf = stackEffectToFeature(effect);
|
||||
s->bonuses.push_back(effect);
|
||||
BonusList sf;
|
||||
s->stackEffectToFeature(sf, effect);
|
||||
BOOST_FOREACH(const Bonus &fromEffect, sf)
|
||||
{
|
||||
s->bonuses.push_back(fromEffect);
|
||||
@ -1258,11 +1103,11 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
|
||||
//removal of negative effects
|
||||
if(resurrected)
|
||||
{
|
||||
for(int h=0; h<changedStack->effects.size(); ++h)
|
||||
for (BonusList::iterator it = changedStack->bonuses.begin(); it != changedStack->bonuses.end(); it++)
|
||||
{
|
||||
if(VLC->spellh->spells[changedStack->effects[h].id].positiveness < 0)
|
||||
if(VLC->spellh->spells[it->id].positiveness < 0)
|
||||
{
|
||||
changedStack->effects.erase(changedStack->effects.begin() + h);
|
||||
changedStack->bonuses.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4305,7 +4305,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
|
||||
sse.stacks.push_back((*it)->ID);
|
||||
}
|
||||
sse.effect.id = spellID;
|
||||
sse.effect.level = spellLvl;
|
||||
sse.effect.val = spellLvl;
|
||||
sse.effect.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
|
||||
if(!sse.stacks.empty())
|
||||
sendAndApply(&sse);
|
||||
|
Loading…
Reference in New Issue
Block a user