mirror of
https://github.com/vcmi/vcmi.git
synced 2025-03-21 21:17:49 +02:00
Partial support for Death Cloud & Magog's Fire Ball.
Lots of refactoring is needed to handle this and multiple-target attacks.
This commit is contained in:
parent
11fade5e67
commit
51943e5f1e
@ -6,8 +6,8 @@
|
||||
#include "CHeroWindow.h"
|
||||
#include "CMessage.h"
|
||||
#include "CKingdomInterface.h"
|
||||
#include <SDL.h>
|
||||
#include <SDL_Extensions.h>
|
||||
#include "SDL.h"
|
||||
#include "SDL_Extensions.h"
|
||||
#include "CBitmapHandler.h"
|
||||
#include "Graphics.h"
|
||||
#include "CSpellWindow.h"
|
||||
|
@ -710,7 +710,17 @@ std::set<CStack*> BattleInfo::getAttackedCreatures( const CSpell * s, int skillL
|
||||
{
|
||||
CStack * st = getStackT(*it, onlyAlive);
|
||||
if(st)
|
||||
attackedCres.insert(st);
|
||||
{
|
||||
if (s->id == 76) //Death Cloud //TODO: fireball and fire immunity
|
||||
{
|
||||
if (st->isLiving() || st->position == destinationTile) //directly hit or alive
|
||||
{
|
||||
attackedCres.insert(st);
|
||||
}
|
||||
}
|
||||
else
|
||||
attackedCres.insert(st);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(s->getTargetType() == CSpell::CREATURE_EXPERT_MASSIVE)
|
||||
|
@ -101,7 +101,7 @@ namespace PrimarySkill
|
||||
BONUS_NAME(BLOCKS_RETALIATION) /*eg. naga*/ \
|
||||
BONUS_NAME(SPELL_IMMUNITY) /*subid - spell id*/ \
|
||||
BONUS_NAME(MANA_CHANNELING) /*value in %, eg. familiar*/ \
|
||||
BONUS_NAME(SPELL_LIKE_ATTACK) /*value - spell id; range is taken from spell, but damage from creature; eg. magog*/ \
|
||||
BONUS_NAME(SPELL_LIKE_ATTACK) /*subtype - spell, value - spell level; range is taken from spell, but damage from creature; eg. magog*/ \
|
||||
BONUS_NAME(THREE_HEADED_ATTACK) /*eg. cerberus*/ \
|
||||
BONUS_NAME(DAEMON_SUMMONING) /*pit lord*/ \
|
||||
BONUS_NAME(FIRE_IMMUNITY) /*subtype 0 - all, 1 - all except positive, 2 - only damage spells*/ \
|
||||
|
@ -1262,7 +1262,7 @@ struct BattleStackAttacked : public CPackForClient//3005
|
||||
|
||||
ui32 stackAttacked, attackerID;
|
||||
ui32 newAmount, newHP, killedAmount, damageAmount;
|
||||
enum EFlags {KILLED = 1, EFFECT = 2};
|
||||
enum EFlags {KILLED = 1, EFFECT = 2, SECONDARY = 4};
|
||||
ui8 flags; //uses EFlags (above)
|
||||
ui32 effect; //set only if flag EFFECT is set
|
||||
std::vector<StacksHealedOrResurrected> healedStacks; //used when life drain
|
||||
@ -1276,6 +1276,10 @@ struct BattleStackAttacked : public CPackForClient//3005
|
||||
{
|
||||
return flags & EFFECT;
|
||||
}
|
||||
bool isSecondary() const//if stack was not a primary target (receives no spell effects)
|
||||
{
|
||||
return flags & SECONDARY;
|
||||
}
|
||||
bool lifeDrain() const //if this attack involves life drain effect
|
||||
{
|
||||
return healedStacks.size() > 0;
|
||||
|
@ -539,48 +539,97 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
|
||||
}
|
||||
|
||||
bsa->damageAmount = gs->curB->calculateDmg(att, def, gs->curB->battleGetOwner(att), gs->curB->battleGetOwner(def), bat.shot(), distance, bat.lucky(), bat.ballistaDoubleDmg());//counting dealt damage
|
||||
|
||||
|
||||
int dmg = bsa->damageAmount;
|
||||
def->prepareAttacked(*bsa);
|
||||
|
||||
//life drain handling
|
||||
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
||||
//TODO: multiple attack targets
|
||||
const Bonus * bonus = att->getBonus(Selector::type(Bonus::SPELL_LIKE_ATTACK));
|
||||
if (bonus)
|
||||
{
|
||||
StacksHealedOrResurrected shi;
|
||||
shi.lifeDrain = (ui8)true;
|
||||
shi.tentHealing = (ui8)false;
|
||||
shi.drainedFrom = def->ID;
|
||||
BattleStackAttacked bss = *bsa; // copy some parameters, such as attacker
|
||||
std::set<CStack*> attackedCreatures = gs->curB->getAttackedCreatures(VLC->spellh->spells[bonus->subtype], bonus->val, att->owner, def->position);
|
||||
|
||||
StacksHealedOrResurrected::HealInfo hi;
|
||||
hi.stackID = att->ID;
|
||||
hi.healedHP = std::min<int>(dmg, att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
|
||||
hi.lowLevelResurrection = false;
|
||||
shi.healedStacks.push_back(hi);
|
||||
|
||||
if (hi.healedHP > 0)
|
||||
BOOST_FOREACH(CStack * stack, attackedCreatures)
|
||||
{
|
||||
bsa->healedStacks.push_back(shi);
|
||||
if (stack != def) //do not hit same stack twice
|
||||
{
|
||||
bss.flags |= BattleStackAttacked::SECONDARY; //all other targets do not suffer from spells & spell-like abilities
|
||||
bss.stackAttacked = stack->ID;
|
||||
bss.damageAmount = gs->curB->calculateDmg(att, stack, gs->curB->battleGetOwner(att),
|
||||
gs->curB->battleGetOwner(stack), bat.shot(), distance, bat.lucky(), bat.ballistaDoubleDmg());
|
||||
bat.bsa.push_back(bss); //add this stack to the list of victims
|
||||
stack->prepareAttacked(bss);
|
||||
|
||||
//life drain handling
|
||||
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && stack->isLiving())
|
||||
{
|
||||
StacksHealedOrResurrected shi;
|
||||
shi.lifeDrain = (ui8)true;
|
||||
shi.tentHealing = (ui8)false;
|
||||
shi.drainedFrom = stack->ID;
|
||||
|
||||
StacksHealedOrResurrected::HealInfo hi;
|
||||
hi.stackID = stack->ID;
|
||||
hi.healedHP = std::min<int>(dmg, att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
|
||||
hi.lowLevelResurrection = false;
|
||||
shi.healedStacks.push_back(hi);
|
||||
|
||||
if (hi.healedHP > 0)
|
||||
{
|
||||
bsa->healedStacks.push_back(shi);
|
||||
}
|
||||
}
|
||||
|
||||
//fire shield handling
|
||||
if (!bat.shot() && stack->hasBonusOfType(Bonus::FIRE_SHIELD) && !att->hasBonusOfType (Bonus::FIRE_IMMUNITY) && !bsa->killed() )
|
||||
{
|
||||
bss.stackAttacked = att->ID; //invert
|
||||
bss.attackerID = stack->ID;
|
||||
bss.flags = BattleStackAttacked::EFFECT; //not seondary - fire shield damages only one creature
|
||||
bss.effect = 11;
|
||||
|
||||
bsa->damageAmount = (dmg * stack->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
||||
att->prepareAttacked(*bsa);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else // only one target
|
||||
{ // TODO: move duplicated code to separate function
|
||||
//life drain handling
|
||||
if (att->hasBonusOfType(Bonus::LIFE_DRAIN) && def->isLiving())
|
||||
{
|
||||
StacksHealedOrResurrected shi;
|
||||
shi.lifeDrain = (ui8)true;
|
||||
shi.tentHealing = (ui8)false;
|
||||
shi.drainedFrom = def->ID;
|
||||
|
||||
//fire shield handling
|
||||
if ( !bat.shot() && def->hasBonusOfType(Bonus::FIRE_SHIELD) && !bsa->killed() )
|
||||
{
|
||||
bat.bsa.push_back(BattleStackAttacked());
|
||||
BattleStackAttacked *bsa = &bat.bsa.back();
|
||||
bsa->stackAttacked = att->ID;
|
||||
bsa->attackerID = def->ID;
|
||||
bsa->flags |= BattleStackAttacked::EFFECT;
|
||||
bsa->effect = 11;
|
||||
StacksHealedOrResurrected::HealInfo hi;
|
||||
hi.stackID = att->ID;
|
||||
hi.healedHP = std::min<int>(dmg, att->MaxHealth() - att->firstHPleft + att->MaxHealth() * (att->baseAmount - att->count) );
|
||||
hi.lowLevelResurrection = false;
|
||||
shi.healedStacks.push_back(hi);
|
||||
|
||||
bsa->damageAmount = (dmg * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
||||
att->prepareAttacked(*bsa);
|
||||
if (hi.healedHP > 0)
|
||||
{
|
||||
bsa->healedStacks.push_back(shi);
|
||||
}
|
||||
}
|
||||
|
||||
//fire shield handling
|
||||
if ( !bat.shot() && def->hasBonusOfType(Bonus::FIRE_SHIELD) && !att->hasBonusOfType (Bonus::FIRE_IMMUNITY) && !bsa->killed() )
|
||||
{
|
||||
bat.bsa.push_back(BattleStackAttacked());
|
||||
BattleStackAttacked *bsa = &bat.bsa.back();
|
||||
bsa->stackAttacked = att->ID;
|
||||
bsa->attackerID = def->ID;
|
||||
bsa->flags |= BattleStackAttacked::EFFECT;
|
||||
bsa->effect = 11;
|
||||
|
||||
bsa->damageAmount = (dmg * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
|
||||
att->prepareAttacked(*bsa);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
|
||||
{
|
||||
@ -4273,9 +4322,9 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||
BOOST_FOREACH(ui32 spellID, spellsToCast)
|
||||
{
|
||||
const CStack * oneOfAttacked = NULL;
|
||||
for(int g=0; g<bat.bsa.size(); ++g)
|
||||
for (int g=0; g<bat.bsa.size(); ++g)
|
||||
{
|
||||
if (bat.bsa[g].newAmount > 0)
|
||||
if (bat.bsa[g].newAmount > 0 && !bat.bsa[g].isSecondary()) //apply effects only to first target stack if it's alive
|
||||
{
|
||||
oneOfAttacked = gs->curB->getStack(bat.bsa[g].stackAttacked);
|
||||
break;
|
||||
|
Loading…
x
Reference in New Issue
Block a user