mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Support for WoG "cast before attack" bonus. Minor fixes.
This commit is contained in:
parent
92006b53f1
commit
79a453f442
@ -5,6 +5,7 @@ RETURN_AFTER_STRIKE Attack and Return Returns after melee attack
|
||||
SPELL_RESISTANCE_AURA Aura of Resistance Nearby stacks get %d% resistance
|
||||
TWO_HEX_ATTACK_BREATH Breath Breath Attack (2-hex range)
|
||||
SPELL_AFTER_ATTACK Caster - %s %d% chance to cast after attack
|
||||
SPELL_BEFORE_ATTACK Caster - %s %d% chance to cast before attack
|
||||
CATAPULT Catapult Attacks siege walls
|
||||
JOUSTING Champion Charge +5% damage per hex travelled
|
||||
DOUBLE_DAMAGE_CHANCE Death Blow %d% chance for double damage
|
||||
|
2
global.h
2
global.h
@ -325,7 +325,7 @@ namespace SpellCasting
|
||||
NO_APPROPRIATE_TARGET, STACK_IMMUNE_TO_SPELL, WRONG_SPELL_TARGET
|
||||
};
|
||||
|
||||
enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING};
|
||||
enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING}; //also includes cast before attack
|
||||
}
|
||||
|
||||
namespace Buildings
|
||||
|
@ -1029,6 +1029,11 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
|
||||
b.type= Bonus::HATE;
|
||||
b.subtype = stringToNumber(mod);
|
||||
break;
|
||||
case 'p':
|
||||
b.type = Bonus::SPELL_BEFORE_ATTACK;
|
||||
b.subtype = stringToNumber(mod);
|
||||
b.additionalInfo = 3; //always expert?
|
||||
break;
|
||||
default:
|
||||
tlog3 << "Not parsed bonus " << buf << mod << "\n";
|
||||
return;
|
||||
|
@ -620,6 +620,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
|
||||
break;
|
||||
case Bonus::SPELL_AFTER_ATTACK:
|
||||
case Bonus::SPELL_BEFORE_ATTACK:
|
||||
{
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
|
||||
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
|
||||
@ -650,6 +651,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
|
||||
break;
|
||||
case Bonus::SPELL_AFTER_ATTACK:
|
||||
case Bonus::SPELL_BEFORE_ATTACK:
|
||||
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
|
||||
break;
|
||||
case Bonus::SPELL_IMMUNITY:
|
||||
@ -683,7 +685,8 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
case Bonus::SPELL_AFTER_ATTACK:
|
||||
fileName = "E_CAST.bmp"; break;
|
||||
//"E_CAST1.bmp"
|
||||
//"E_CAST2.bmp"
|
||||
case Bonus::SPELL_BEFORE_ATTACK:
|
||||
fileName ="E_CAST2.bmp"; break;
|
||||
//"E_CASTER.bmp"
|
||||
case Bonus::JOUSTING:
|
||||
fileName = "E_CHAMP.bmp"; break;
|
||||
|
@ -93,6 +93,7 @@ namespace PrimarySkill
|
||||
BONUS_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
|
||||
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
|
||||
BONUS_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||
BONUS_NAME(SPELL_BEFORE_ATTACK) /* subtype - spell id, value - chance %, additional info % 1000 - level, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||
BONUS_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
||||
BONUS_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
|
||||
BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
||||
|
@ -3046,6 +3046,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
//attack
|
||||
BattleAttack bat;
|
||||
prepareAttack(bat, curStack, stackAtEnd, distance, ba.additionalInfo);
|
||||
handleAttackBeforeCasting(bat); //only before first attack
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
|
||||
@ -3096,6 +3097,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
BattleAttack bat;
|
||||
bat.flags |= BattleAttack::SHOT;
|
||||
prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
|
||||
handleAttackBeforeCasting(bat);
|
||||
sendAndApply(&bat);
|
||||
handleAfterAttackCasting(bat);
|
||||
|
||||
@ -3107,7 +3109,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
||||
prepareAttack(bat2, curStack, destStack, 0, ba.destinationTile);
|
||||
sendAndApply(&bat2);
|
||||
}
|
||||
|
||||
//TODO: allow more than one additional attack
|
||||
if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
|
||||
&& curStack->alive()
|
||||
&& destStack->alive()
|
||||
@ -3473,7 +3475,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
|
||||
continue;
|
||||
|
||||
BattleStackAttacked bsa;
|
||||
if (destination > -1 && (*it)->coversPos(destination)) //display effect only upon primary target of area spell
|
||||
if (destination > -1 && (*it)->coversPos(destination) || spell->range[spellLvl] == "X") //display effect only upon primary target of area spell
|
||||
{
|
||||
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||
bsa.effect = spell->mainEffectAnim;
|
||||
@ -4317,13 +4319,12 @@ bool CGameHandler::dig( const CGHeroInstance *h )
|
||||
return true;
|
||||
}
|
||||
|
||||
void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker)
|
||||
{
|
||||
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
||||
if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
|
||||
if(attacker->hasBonusOfType(attackMode))
|
||||
{
|
||||
std::set<ui32> spellsToCast;
|
||||
boost::shared_ptr<BonusList> spells = attacker->getBonuses(Selector::type(Bonus::SPELL_AFTER_ATTACK));
|
||||
boost::shared_ptr<BonusList> spells = attacker->getBonuses(Selector::type(attackMode));
|
||||
BOOST_FOREACH(const Bonus *sf, *spells)
|
||||
{
|
||||
spellsToCast.insert (sf->subtype);
|
||||
@ -4344,7 +4345,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
if(oneOfAttacked == NULL) //all attacked creatures have been killed
|
||||
return;
|
||||
int spellLevel = 0;
|
||||
boost::shared_ptr<BonusList> spellsByType = attacker->getBonuses(Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID));
|
||||
boost::shared_ptr<BonusList> spellsByType = attacker->getBonuses(Selector::typeSubtype(attackMode, spellID));
|
||||
BOOST_FOREACH(const Bonus *sf, *spellsByType)
|
||||
{
|
||||
amax(spellLevel, sf->additionalInfo % 1000); //pick highest level
|
||||
@ -4352,24 +4353,36 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
if (meleeRanged == 0 || (meleeRanged == 1 && bat.shot()) || (meleeRanged == 2 && !bat.shot()))
|
||||
castMe = true;
|
||||
}
|
||||
int chance = attacker->valOfBonuses((Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID)));
|
||||
int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID)));
|
||||
amin (chance, 100);
|
||||
int destination = oneOfAttacked->position;
|
||||
|
||||
const CSpell * spell = VLC->spellh->spells[spellID];
|
||||
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position)
|
||||
!= SpellCasting::OK)
|
||||
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position) != SpellCasting::OK)
|
||||
continue;
|
||||
|
||||
//check if spell should be casted (probability handling)
|
||||
if(rand()%100 >= chance)
|
||||
continue;
|
||||
|
||||
//casting
|
||||
//casting //TODO: check if spell can be blocked or target is immune
|
||||
if (castMe) //stacks use 0 spell power. If needed, default = 3 or custom value is used
|
||||
handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL, 0, SpellCasting::AFTER_ATTACK_CASTING, attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CGameHandler::handleAttackBeforeCasting (const BattleAttack & bat)
|
||||
{
|
||||
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
||||
attackCasting(bat, Bonus::SPELL_BEFORE_ATTACK, attacker); //no detah stare / acid bretah needed?
|
||||
}
|
||||
|
||||
void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
{
|
||||
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
||||
attackCasting(bat, Bonus::SPELL_AFTER_ATTACK, attacker);
|
||||
|
||||
if (attacker->hasBonusOfType(Bonus::DEATH_STARE)) // spell id 79
|
||||
{
|
||||
int staredCreatures = 0;
|
||||
|
@ -249,7 +249,9 @@ public:
|
||||
|
||||
void run(bool resume);
|
||||
void newTurn();
|
||||
void handleAfterAttackCasting( const BattleAttack & bat );
|
||||
void handleAttackBeforeCasting (const BattleAttack & bat);
|
||||
void handleAfterAttackCasting (const BattleAttack & bat);
|
||||
void attackCasting(const BattleAttack & bat, Bonus::BonusType attackMode, const CStack * attacker);
|
||||
bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, int slot);
|
||||
friend class CVCMIServer;
|
||||
friend class CScriptCallback;
|
||||
|
Loading…
Reference in New Issue
Block a user