mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-23 00:28:08 +02:00
* new spell: blind
* a part of hypnotize support * minor changes and bugfixes
This commit is contained in:
@ -1462,6 +1462,8 @@ bool CBattleInterface::isTileAttackable(const int & number) const
|
||||
void CBattleInterface::handleEndOfMove(int stackNumber, int destinationTile)
|
||||
{
|
||||
const CStack * movedStack = LOCPLINT->cb->battleGetStackByID(stackNumber);
|
||||
if(!movedStack)
|
||||
return;
|
||||
if(creAnims[stackNumber]->framesInGroup(21)!=0) // some units don't have this animation (ie. halberdier)
|
||||
{
|
||||
if (movedStack->creature->sounds.endMoving)
|
||||
@ -2199,7 +2201,7 @@ void CBattleInterface::redrawBackgroundWithHexes(int activeStack)
|
||||
void CBattleInterface::printConsoleAttacked(int ID, int dmg, int killed, int IDby)
|
||||
{
|
||||
char tabh[200];
|
||||
const CStack * attacker = LOCPLINT->cb->battleGetStackByID(IDby);
|
||||
const CStack * attacker = LOCPLINT->cb->battleGetStackByID(IDby, false);
|
||||
const CStack * defender = LOCPLINT->cb->battleGetStackByID(ID, false);
|
||||
int end = sprintf(tabh, CGI->generaltexth->allTexts[attacker->amount > 1 ? 377 : 376].c_str(),
|
||||
(attacker->amount > 1 ? attacker->creature->namePl.c_str() : attacker->creature->nameSing.c_str()),
|
||||
|
@ -29,7 +29,7 @@
|
||||
26 -1 12 X X X X
|
||||
27 1 27 0 0 0 X
|
||||
28 1 2 0 0 0 X
|
||||
29 1 -1 0 0 0 X
|
||||
29 1 11 0 0 0 X
|
||||
30 1 22 0 0 0 X
|
||||
31 1 24 0 0 0 X
|
||||
32 1 23 0 0 0 X
|
||||
@ -58,11 +58,11 @@
|
||||
55 1 28 0 0 0 0
|
||||
56 1 17 0 0 0 0
|
||||
57 -1 -1 0 0 0 0
|
||||
58 1 -1 0 0 0 X
|
||||
59 -1 -1 0 0 0-1 0-2
|
||||
60 -1 -1 0 0 0 0
|
||||
58 1 7 0 0 0 X
|
||||
59 -1 35 0 0 0-1 0-2
|
||||
60 -1 21 0 0 0 0
|
||||
61 -1 42 0 0 0 X
|
||||
62 -1 -1 0 0 0 0
|
||||
62 -1 6 0 0 0 0
|
||||
63 1 -1 0 0 0 0
|
||||
64 0 -1 X X X X
|
||||
65 1 -1 0 0 0 0
|
||||
|
@ -1861,7 +1861,7 @@ bool CGameState::checkForVisitableDir(const int3 & src, const int3 & dst) const
|
||||
|
||||
int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting)
|
||||
{
|
||||
int attackDefenseBonus = attacker->Attack() - defender->Defense(),
|
||||
int attackDefenseBonus,
|
||||
minDmg = attacker->creature->damageMin * attacker->amount,
|
||||
maxDmg = attacker->creature->damageMax * attacker->amount;
|
||||
|
||||
@ -1871,6 +1871,15 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
|
||||
maxDmg *= attackerHero->getPrimSkillLevel(0) + 1;
|
||||
}
|
||||
|
||||
if(attacker->hasFeatureOfType(StackFeature::GENERAL_ATTACK_REDUCTION))
|
||||
{
|
||||
attackDefenseBonus = attacker->Attack() * (attacker->valOfFeatures(StackFeature::GENERAL_ATTACK_REDUCTION, -1024) / 100.0f) - defender->Defense();
|
||||
}
|
||||
else
|
||||
{
|
||||
attackDefenseBonus = attacker->Attack() - defender->Defense();
|
||||
}
|
||||
|
||||
//calculating total attack/defense skills modifier
|
||||
|
||||
if(!shooting && attacker->hasFeatureOfType(StackFeature::ATTACK_BONUS, 0)) //bloodlust handling (etc.)
|
||||
@ -1883,6 +1892,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
|
||||
attackDefenseBonus += attacker->valOfFeatures(StackFeature::ATTACK_BONUS, 1);
|
||||
}
|
||||
|
||||
|
||||
if(attacker->getEffect(55)) //slayer handling
|
||||
{
|
||||
std::vector<int> affectedIds;
|
||||
|
@ -600,7 +600,7 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
|
||||
s->features.clear();
|
||||
for(int i=0; i < tmpFeatures.size(); i++)
|
||||
{
|
||||
if(tmpFeatures[i].duration == StackFeature::N_TURNS)
|
||||
if((tmpFeatures[i].duration & StackFeature::N_TURNS) != 0)
|
||||
{
|
||||
tmpFeatures[i].turnsRemain--;
|
||||
if(tmpFeatures[i].turnsRemain > 0)
|
||||
@ -663,6 +663,29 @@ DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
|
||||
attacker->shots--;
|
||||
BOOST_FOREACH(BattleStackAttacked stackAttacked, bsa)
|
||||
stackAttacked.applyGs(gs);
|
||||
|
||||
for(int g=0; g<attacker->features.size(); ++g)
|
||||
{
|
||||
if((attacker->features[g].duration & StackFeature::UNTIL_ATTACK) != 0)
|
||||
{
|
||||
attacker->features.erase(attacker->features.begin() + g);
|
||||
g = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for(std::set<BattleStackAttacked>::const_iterator it = bsa.begin(); it != bsa.end(); ++it)
|
||||
{
|
||||
CStack * stack = gs->curB->getStack(it->stackAttacked, false);
|
||||
|
||||
for(int g=0; g<stack->features.size(); ++g)
|
||||
{
|
||||
if((stack->features[g].duration & StackFeature::UNITL_BEING_ATTACKED) != 0)
|
||||
{
|
||||
stack->features.erase(stack->features.begin() + g);
|
||||
g = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORT void StartAction::applyGs( CGameState *gs )
|
||||
@ -841,11 +864,18 @@ static std::vector<StackFeature> stackEffectToFeature(const CStack::StackEffect
|
||||
case 55: //slayer
|
||||
sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
|
||||
break;
|
||||
case 56: //frenzy
|
||||
sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
|
||||
break;
|
||||
case 60: //hypnotize
|
||||
break;
|
||||
sf.push_back(featureGenerator(StackFeature::HYPNOTIZED, 0, sse.level, sse.turnsRemain));
|
||||
case 61: //forgetfulness
|
||||
sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
|
||||
break;
|
||||
case 56: //frenzy
|
||||
sf.push_back(featureGenerator(StackFeature::SLAYER, 0, sse.level, sse.turnsRemain));
|
||||
case 62: //blind
|
||||
sf.push_back(makeFeature(StackFeature::NOT_ACTIVE, StackFeature::UNITL_BEING_ATTACKED | StackFeature::N_TURNS, 0, 0, StackFeature::SPELL_EFFECT, sse.turnsRemain, 0));
|
||||
sf.push_back(makeFeature(StackFeature::GENERAL_ATTACK_REDUCTION, StackFeature::UNTIL_ATTACK | StackFeature::N_TURNS, 0, VLC->spellh->spells[sse.id].powers[sse.level], StackFeature::SPELL_EFFECT, sse.turnsRemain, 0));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,8 @@ struct StackFeature
|
||||
VCMI_CREATURE_ABILITY_NAME(SPELLCASTER) /*subtype - spell id, value - level of school, additional info - spell power*/ \
|
||||
VCMI_CREATURE_ABILITY_NAME(CATAPULT) \
|
||||
VCMI_CREATURE_ABILITY_NAME(ENEMY_DEFENCE_REDUCTION) /*in % (value) eg. behemots*/ \
|
||||
VCMI_CREATURE_ABILITY_NAME(GENERAL_DAMAGE_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \
|
||||
VCMI_CREATURE_ABILITY_NAME(GENERAL_DAMAGE_REDUCTION) /* shield / air shield effect */ \
|
||||
VCMI_CREATURE_ABILITY_NAME(GENERAL_ATTACK_REDUCTION) /*eg. while stoned or blinded - in %, subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage*/ \
|
||||
VCMI_CREATURE_ABILITY_NAME(ATTACKS_ALL_ADJACENT) /*eg. hydra*/ \
|
||||
VCMI_CREATURE_ABILITY_NAME(MORE_DAMAGE_FROM_SPELL) /*value - damage increase in %, subtype - spell id*/ \
|
||||
VCMI_CREATURE_ABILITY_NAME(CASTS_SPELL_WHEN_KILLED) /*similar to spell after attack*/ \
|
||||
@ -92,10 +93,10 @@ struct StackFeature
|
||||
|
||||
enum EDuration
|
||||
{
|
||||
WHOLE_BATTLE,
|
||||
N_TURNS,
|
||||
UNITL_BEING_ATTACKED,/*removed after attack and counterattacks are performed*/
|
||||
UNTIL_ATTACK /*removed after attack and counterattacks are performed*/
|
||||
WHOLE_BATTLE = 1,
|
||||
N_TURNS = 2,
|
||||
UNITL_BEING_ATTACKED = 4,/*removed after attack and counterattacks are performed*/
|
||||
UNTIL_ATTACK = 8 /*removed after attack and counterattacks are performed*/
|
||||
};
|
||||
|
||||
enum ESource
|
||||
@ -107,7 +108,7 @@ struct StackFeature
|
||||
};
|
||||
|
||||
ui8 type;//ECombatFeatures
|
||||
ui8 duration;//EDuration
|
||||
ui8 duration;//EDuration //bitfield
|
||||
ui8 source;//ESource
|
||||
si8 positiveness; //+1 - positive, 0 - neutral, -1 - negative; used mostly for spell features
|
||||
ui16 turnsRemain; //if duration is N_TURNS it describes how long the effect will last
|
||||
@ -129,7 +130,7 @@ struct StackFeature
|
||||
};
|
||||
|
||||
//generates StackFeature from given data
|
||||
inline StackFeature makeFeature(StackFeature::ECombatFeatures type, StackFeature::EDuration duration, si16 subtype, si32 value, StackFeature::ESource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
|
||||
inline StackFeature makeFeature(StackFeature::ECombatFeatures type, ui8 duration, si16 subtype, si32 value, StackFeature::ESource source, ui16 turnsRemain = 0, si32 additionalInfo = 0)
|
||||
{
|
||||
StackFeature sf;
|
||||
sf.type = type;
|
||||
|
@ -2332,7 +2332,8 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION)
|
||||
&& stackAtEnd->alive()
|
||||
&& stackAtEnd->counterAttacks
|
||||
&& !stackAtEnd->hasFeatureOfType(StackFeature::SIEGE_WEAPON)) //TODO: support for multiple retaliatons per turn
|
||||
&& !stackAtEnd->hasFeatureOfType(StackFeature::SIEGE_WEAPON)
|
||||
&& !stackAtEnd->hasFeatureOfType(StackFeature::HYPNOTIZED)) //TODO: support for multiple retaliatons per turn
|
||||
{
|
||||
prepareAttack(bat,stackAtEnd,curStack);
|
||||
bat.flags |= 2;
|
||||
@ -2654,6 +2655,21 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
|
||||
ret.push_back((*it)->ID);
|
||||
|
||||
}
|
||||
|
||||
if(sp->id == 60) //hypnotize
|
||||
{
|
||||
for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
|
||||
{
|
||||
if( (*it)->amount * (*it)->MaxHealth() + (*it)->firstHPleft
|
||||
>
|
||||
caster->getPrimSkillLevel(2) * 25 + sp->powers[caster->getSpellSchoolLevel(sp)]
|
||||
)
|
||||
{
|
||||
ret.push_back((*it)->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2767,7 +2783,9 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
case 54: //slow
|
||||
case 55: //slayer
|
||||
case 56: //frenzy
|
||||
case 60: //hypnotize
|
||||
case 61: //forgetfulness
|
||||
case 62: //blind
|
||||
{
|
||||
SetStackEffect sse;
|
||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||
|
Reference in New Issue
Block a user