mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- Drain Life now has % effect depending on bonus value
- Stack can use more than 2 attacks. Additional attacks can now be seperated as "ONLY_MELEE_FIGHT and "ONLY_DISTANCE_FIGHT".
This commit is contained in:
parent
043c7c52a3
commit
140786a04b
@ -15,7 +15,7 @@
|
||||
{ "id": "DEFENSIVE_STANCE", "name": "Defense Bonus", "description": "+%d Defense when defending" },
|
||||
{ "id": "ADDITIONAL_ATTACK", "name": "Double Strike", "description": "Attacks twice" },
|
||||
{ "id": "DRAGON_NATURE", "name": "Dragon", "description": "Creature has a Dragon Nature" },
|
||||
{ "id": "LIFE_DRAIN", "name": "Drain life", "description": "Drains life equal to damage dealt" },
|
||||
{ "id": "LIFE_DRAIN", "name": "Drain life (%d%)", "description": "Drains life equal to damage dealt" },
|
||||
{ "id": "FEAR", "name": "Fear", "description": "Causes Fear on an enemy stack" },
|
||||
{ "id": "FEARLESS", "name": "Fearless", "description": "Immune to Fear ability" },
|
||||
{ "id": "FLYING", "name": "Fly", "description": "Can Fly (ignores obstacles)" },
|
||||
|
@ -152,6 +152,7 @@
|
||||
"id": 7,
|
||||
"level": 4,
|
||||
"faction": "castle",
|
||||
"abilities": [ [ "ADDITIONAL_ATTACK", 1, 0, 0 ] ],
|
||||
"graphics" :
|
||||
{
|
||||
"animation": "CCRUSD.DEF"
|
||||
|
@ -142,7 +142,7 @@
|
||||
"id": 63,
|
||||
"level": 4,
|
||||
"faction": "necropolis",
|
||||
"abilities": [ [ "LIFE_DRAIN", 0, 0, 0 ],
|
||||
"abilities": [ [ "LIFE_DRAIN", 100, 0, 0 ], //drain 100% of damage dealt
|
||||
[ "BLOCKS_RETALIATION", 0, 0, 0 ] ], //vampire lords
|
||||
"graphics" :
|
||||
{
|
||||
|
@ -107,6 +107,13 @@
|
||||
"id": 19,
|
||||
"level": 3,
|
||||
"faction": "rampart",
|
||||
"abilities": [
|
||||
{
|
||||
"type": "ADDITIONAL_ATTACK",
|
||||
"val" : 1,
|
||||
"effectRange": "ONLY_DISTANCE_FIGHT"
|
||||
}
|
||||
],
|
||||
"graphics" :
|
||||
{
|
||||
"animation": "CGRELF.DEF",
|
||||
|
@ -50,7 +50,8 @@
|
||||
"id": 154,
|
||||
"level": 8,
|
||||
"faction": "necropolis",
|
||||
"abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ], //blood dragon is a dragon
|
||||
"abilities": [ [ "LIFE_DRAIN", 40, 0, 0 ], //40%
|
||||
[ "DRAGON_NATURE", 0, 0, 0 ] ], //blood dragon is a dragon
|
||||
"graphics" :
|
||||
{
|
||||
"animation": "ZM154Z.DEF"
|
||||
|
@ -263,8 +263,6 @@ void CCreatureHandler::loadCreatures()
|
||||
ncre.addBonus(0, Bonus::SHOOTER);
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "SIEGE_WEAPON"))
|
||||
ncre.addBonus(0, Bonus::SIEGE_WEAPON);
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "const_two_attacks"))
|
||||
ncre.addBonus(1, Bonus::ADDITIONAL_ATTACK);
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "const_free_attack"))
|
||||
ncre.addBonus(0, Bonus::BLOCKS_RETALIATION);
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "IS_UNDEAD"))
|
||||
@ -324,7 +322,10 @@ void CCreatureHandler::loadCreatures()
|
||||
}
|
||||
BOOST_FOREACH(const JsonNode &ability, node.second["abilities"].Vector())
|
||||
{
|
||||
AddAbility(c, ability.Vector());
|
||||
if (ability.getType() == JsonNode::DATA_VECTOR)
|
||||
AddAbility(c, ability.Vector());
|
||||
else
|
||||
c->addNewBonus(JsonUtils::parseBonus(ability));
|
||||
}
|
||||
|
||||
loadCreatureJson(c, node.second);
|
||||
|
@ -593,8 +593,9 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
case Bonus::ATTACKS_ALL_ADJACENT:
|
||||
case Bonus::ADDITIONAL_ATTACK: //TODO: what with more than one attack? Axe of Ferocity for example
|
||||
case Bonus::FULL_HP_REGENERATION:
|
||||
case Bonus::MANA_DRAIN:
|
||||
case Bonus::LIFE_DRAIN:
|
||||
case Bonus::REBIRTH:
|
||||
case Bonus::LIFE_DRAIN: //TODO: chance, hp percentage?
|
||||
case Bonus::SELF_MORALE:
|
||||
case Bonus::SELF_LUCK:
|
||||
case Bonus::FEAR:
|
||||
@ -616,7 +617,6 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
case Bonus::SPELL_RESISTANCE_AURA:
|
||||
case Bonus::SPELL_DAMAGE_REDUCTION:
|
||||
case Bonus::LEVEL_SPELL_IMMUNITY:
|
||||
case Bonus::MANA_DRAIN:
|
||||
case Bonus::HP_REGENERATION:
|
||||
case Bonus::ADDITIONAL_RETALIATION:
|
||||
case Bonus::DEFENSIVE_STANCE:
|
||||
@ -667,6 +667,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
case Bonus::ENEMY_DEFENCE_REDUCTION:
|
||||
case Bonus::REBIRTH:
|
||||
case Bonus::DEATH_STARE:
|
||||
case Bonus::LIFE_DRAIN:
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
|
||||
break;
|
||||
case Bonus::HATE:
|
||||
@ -905,6 +906,8 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
fileName = "ManaChannel.bmp"; break;
|
||||
case Bonus::MANA_DRAIN:
|
||||
fileName = "ManaDrain.bmp"; break;
|
||||
case Bonus::LIFE_DRAIN:
|
||||
fileName = "DrainLife.bmp"; break;
|
||||
}
|
||||
if(!fileName.empty())
|
||||
fileName = "zvs/Lib1.res/" + fileName;
|
||||
|
@ -863,7 +863,8 @@ void CGameHandler::applyBattleEffects(BattleAttack &bat, const CStack *att, cons
|
||||
|
||||
StacksHealedOrResurrected::HealInfo hi;
|
||||
hi.stackID = att->ID;
|
||||
hi.healedHP = std::min<int>(bsa.damageAmount, att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
|
||||
hi.healedHP = std::min<int> (bsa.damageAmount * att->valOfBonuses (Bonus::LIFE_DRAIN) / 100,
|
||||
att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
|
||||
hi.lowLevelResurrection = false;
|
||||
shi.healedStacks.push_back(hi);
|
||||
|
||||
@ -3457,38 +3458,32 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
}
|
||||
|
||||
//attack
|
||||
if(stack->alive()) //move can cause death, eg. by walking into the moat
|
||||
{
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, stack, stackAtEnd, distance, ba.additionalInfo);
|
||||
handleAttackBeforeCasting(bat); //only before first attack
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
}
|
||||
|
||||
//counterattack
|
||||
if(!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
||||
&& stackAtEnd->ableToRetaliate()
|
||||
&& stack->alive()) //attacker may have died (fire shield)
|
||||
{
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
|
||||
bat.flags |= BattleAttack::COUNTER;
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
}
|
||||
int totalAttacks = 1 + stack->getBonuses(Selector::type (Bonus::ADDITIONAL_ATTACK),
|
||||
(Selector::effectRange (Bonus::NO_LIMIT) || Selector::effectRange(Bonus::ONLY_MELEE_FIGHT)))->totalValue(); //all unspicified attacks + melee attacks
|
||||
|
||||
//second attack
|
||||
if(stack //FIXME: clones tend to disapear during actions
|
||||
&& stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0
|
||||
&& !stack->hasBonusOfType(Bonus::SHOOTER)
|
||||
&& stack->alive()
|
||||
&& stackAtEnd->alive() )
|
||||
for (int i = 0; i < totalAttacks; ++i)
|
||||
{
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, stack, stackAtEnd, 0, ba.additionalInfo);
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
if( stack &&stack->alive()) //move can cause death, eg. by walking into the moat
|
||||
{
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, stack, stackAtEnd, distance, ba.additionalInfo);
|
||||
handleAttackBeforeCasting(bat); //only before first attack
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
}
|
||||
|
||||
//counterattack
|
||||
if(!stack->hasBonusOfType(Bonus::BLOCKS_RETALIATION)
|
||||
&& stackAtEnd->ableToRetaliate()
|
||||
&& stack->alive()) //attacker may have died (fire shield)
|
||||
{
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, stackAtEnd, stack, 0, stack->position);
|
||||
bat.flags |= BattleAttack::COUNTER;
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
}
|
||||
}
|
||||
|
||||
//return
|
||||
@ -3529,18 +3524,24 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
prepareAttack(bat2, stack, destStack, 0, ba.destinationTile);
|
||||
sendAndApply(&bat2);
|
||||
}
|
||||
//TODO: allow more than one additional attack
|
||||
if(stack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
|
||||
&& stack->alive()
|
||||
&& destStack->alive()
|
||||
&& stack->shots
|
||||
)
|
||||
//allow more than one additional attack
|
||||
|
||||
int additionalAttacks = stack->getBonuses(Selector::type (Bonus::ADDITIONAL_ATTACK),
|
||||
(Selector::effectRange (Bonus::NO_LIMIT) || Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT)))->totalValue();
|
||||
for (int i = 0; i < additionalAttacks; ++i)
|
||||
{
|
||||
BattleAttack bat;
|
||||
bat.flags |= BattleAttack::SHOT;
|
||||
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
if(
|
||||
stack->alive()
|
||||
&& destStack->alive()
|
||||
&& stack->shots
|
||||
)
|
||||
{
|
||||
BattleAttack bat;
|
||||
bat.flags |= BattleAttack::SHOT;
|
||||
prepareAttack(bat, stack, destStack, 0, ba.destinationTile);
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
}
|
||||
}
|
||||
|
||||
sendAndApply(&end_action);
|
||||
|
Loading…
Reference in New Issue
Block a user