1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

Support for WoG "cast before attack" bonus. Minor fixes.

This commit is contained in:
DjWarmonger 2011-07-16 06:42:44 +00:00
parent 92006b53f1
commit 79a453f442
7 changed files with 39 additions and 14 deletions

View File

@ -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 SPELL_RESISTANCE_AURA Aura of Resistance Nearby stacks get %d% resistance
TWO_HEX_ATTACK_BREATH Breath Breath Attack (2-hex range) TWO_HEX_ATTACK_BREATH Breath Breath Attack (2-hex range)
SPELL_AFTER_ATTACK Caster - %s %d% chance to cast after attack 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 CATAPULT Catapult Attacks siege walls
JOUSTING Champion Charge +5% damage per hex travelled JOUSTING Champion Charge +5% damage per hex travelled
DOUBLE_DAMAGE_CHANCE Death Blow %d% chance for double damage DOUBLE_DAMAGE_CHANCE Death Blow %d% chance for double damage

View File

@ -325,7 +325,7 @@ namespace SpellCasting
NO_APPROPRIATE_TARGET, STACK_IMMUNE_TO_SPELL, WRONG_SPELL_TARGET 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 namespace Buildings

View File

@ -1029,6 +1029,11 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
b.type= Bonus::HATE; b.type= Bonus::HATE;
b.subtype = stringToNumber(mod); b.subtype = stringToNumber(mod);
break; break;
case 'p':
b.type = Bonus::SPELL_BEFORE_ATTACK;
b.subtype = stringToNumber(mod);
b.additionalInfo = 3; //always expert?
break;
default: default:
tlog3 << "Not parsed bonus " << buf << mod << "\n"; tlog3 << "Not parsed bonus " << buf << mod << "\n";
return; return;

View File

@ -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); boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
break; break;
case Bonus::SPELL_AFTER_ATTACK: 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, "%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); 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)); boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
break; break;
case Bonus::SPELL_AFTER_ATTACK: case Bonus::SPELL_AFTER_ATTACK:
case Bonus::SPELL_BEFORE_ATTACK:
boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name); boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
break; break;
case Bonus::SPELL_IMMUNITY: case Bonus::SPELL_IMMUNITY:
@ -683,7 +685,8 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
case Bonus::SPELL_AFTER_ATTACK: case Bonus::SPELL_AFTER_ATTACK:
fileName = "E_CAST.bmp"; break; fileName = "E_CAST.bmp"; break;
//"E_CAST1.bmp" //"E_CAST1.bmp"
//"E_CAST2.bmp" case Bonus::SPELL_BEFORE_ATTACK:
fileName ="E_CAST2.bmp"; break;
//"E_CASTER.bmp" //"E_CASTER.bmp"
case Bonus::JOUSTING: case Bonus::JOUSTING:
fileName = "E_CHAMP.bmp"; break; fileName = "E_CHAMP.bmp"; break;

View File

@ -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_ALLY) /*in mana points (value) , eg. mage*/ \
BONUS_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \ 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_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(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(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*/ \ BONUS_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \

View File

@ -3046,6 +3046,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
//attack //attack
BattleAttack bat; BattleAttack bat;
prepareAttack(bat, curStack, stackAtEnd, distance, ba.additionalInfo); prepareAttack(bat, curStack, stackAtEnd, distance, ba.additionalInfo);
handleAttackBeforeCasting(bat); //only before first attack
sendAndApply(&bat); sendAndApply(&bat);
handleAfterAttackCasting(bat); handleAfterAttackCasting(bat);
@ -3096,6 +3097,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
BattleAttack bat; BattleAttack bat;
bat.flags |= BattleAttack::SHOT; bat.flags |= BattleAttack::SHOT;
prepareAttack(bat, curStack, destStack, 0, ba.destinationTile); prepareAttack(bat, curStack, destStack, 0, ba.destinationTile);
handleAttackBeforeCasting(bat);
sendAndApply(&bat); sendAndApply(&bat);
handleAfterAttackCasting(bat); handleAfterAttackCasting(bat);
@ -3107,7 +3109,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
prepareAttack(bat2, curStack, destStack, 0, ba.destinationTile); prepareAttack(bat2, curStack, destStack, 0, ba.destinationTile);
sendAndApply(&bat2); 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 if(curStack->valOfBonuses(Bonus::ADDITIONAL_ATTACK) > 0 //if unit shots twice let's make another shot
&& curStack->alive() && curStack->alive()
&& destStack->alive() && destStack->alive()
@ -3473,7 +3475,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, THex destinati
continue; continue;
BattleStackAttacked bsa; 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.flags |= BattleStackAttacked::EFFECT;
bsa.effect = spell->mainEffectAnim; bsa.effect = spell->mainEffectAnim;
@ -4317,13 +4319,12 @@ bool CGameHandler::dig( const CGHeroInstance *h )
return true; 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(attackMode))
if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
{ {
std::set<ui32> spellsToCast; 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) BOOST_FOREACH(const Bonus *sf, *spells)
{ {
spellsToCast.insert (sf->subtype); spellsToCast.insert (sf->subtype);
@ -4344,7 +4345,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
if(oneOfAttacked == NULL) //all attacked creatures have been killed if(oneOfAttacked == NULL) //all attacked creatures have been killed
return; return;
int spellLevel = 0; 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) BOOST_FOREACH(const Bonus *sf, *spellsByType)
{ {
amax(spellLevel, sf->additionalInfo % 1000); //pick highest level 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())) if (meleeRanged == 0 || (meleeRanged == 1 && bat.shot()) || (meleeRanged == 2 && !bat.shot()))
castMe = true; castMe = true;
} }
int chance = attacker->valOfBonuses((Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID))); int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID)));
amin (chance, 100); amin (chance, 100);
int destination = oneOfAttacked->position; int destination = oneOfAttacked->position;
const CSpell * spell = VLC->spellh->spells[spellID]; const CSpell * spell = VLC->spellh->spells[spellID];
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position) if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, SpellCasting::AFTER_ATTACK_CASTING, oneOfAttacked->position) != SpellCasting::OK)
!= SpellCasting::OK)
continue; continue;
//check if spell should be casted (probability handling) //check if spell should be casted (probability handling)
if(rand()%100 >= chance) if(rand()%100 >= chance)
continue; 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 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); 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 if (attacker->hasBonusOfType(Bonus::DEATH_STARE)) // spell id 79
{ {
int staredCreatures = 0; int staredCreatures = 0;

View File

@ -249,7 +249,9 @@ public:
void run(bool resume); void run(bool resume);
void newTurn(); void newTurn();
void handleAttackBeforeCasting (const BattleAttack & bat);
void handleAfterAttackCasting (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); bool sacrificeArtifact(const IMarket * m, const CGHeroInstance * hero, int slot);
friend class CVCMIServer; friend class CVCMIServer;
friend class CScriptCallback; friend class CScriptCallback;