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

* life drain implemented

* fixed #134
* fixed damage calculation formula
This commit is contained in:
mateuszb 2010-05-07 12:29:41 +00:00
parent cc616616c1
commit dbbbaa1e18
10 changed files with 147 additions and 46 deletions

View File

@ -106,13 +106,14 @@ public:
virtual void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa){}; //called when stack receives damage (after battleAttack())
virtual void battleEnd(BattleResult *br){};
virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
virtual void battleNewRoundFirst(int round){}; //called at the beginning of each turn before changes are applied;
virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
virtual void battleStackMoved(int ID, int dest, int distance, bool end){};
virtual void battleSpellCast(SpellCast *sc){};
virtual void battleStacksEffectsSet(SetStackEffect & sse){};//called when a specific effect is set to stacks
virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom){}; //called when stacks are healed / resurrected first element of pair - stack id, second - healed hp
virtual void battleNewStackAppeared(int stackID){}; //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles){}; //called when a certain set of obstacles is removed from batlefield; IDs of them are given
virtual void battleCatapultAttacked(const CatapultAttack & ca){}; //called when catapult makes an attack

View File

@ -2227,18 +2227,18 @@ void CBattleInterface::stackAttacking(int ID, int dest, int attackedID)
addNewAnim(new CMeleeAttack(this, ID, dest, attackedID));
}
void CBattleInterface::newRound(int number)
void CBattleInterface::newRoundFirst( int round )
{
console->addText(CGI->generaltexth->allTexts[412]);
//unlock spellbook
//bSpell->block(!curInt->cb->battleCanCastSpell());
//don't unlock spellbook - this should be done when we have axctive creature
//handle regeneration
std::map<int, CStack> stacks = curInt->cb->battleGetStacks();
for(std::map<int, CStack>::const_iterator it = stacks.begin(); it != stacks.end(); ++it)
{
//don't show animation when no HP is regenerated
if (it->second.firstHPleft == it->second.MaxHealth())
{
continue;
}
if( it->second.hasBonusOfType(Bonus::HP_REGENERATION) && it->second.alive() )
displayEffect(74, it->second.position);
@ -2250,6 +2250,17 @@ void CBattleInterface::newRound(int number)
}
}
void CBattleInterface::newRound(int number)
{
console->addText(CGI->generaltexth->allTexts[412]);
//unlock spellbook
//bSpell->block(!curInt->cb->battleCanCastSpell());
//don't unlock spellbook - this should be done when we have axctive creature
}
void CBattleInterface::giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional)
{
if(!curInt->cb->battleGetStackByID(stack) && action != 1 && action != 4 && action != 5)
@ -3237,6 +3248,7 @@ void CBattleInterface::startAction(const BattleAction* action)
}
}
void CBattleHero::show(SDL_Surface *to)
{
//animation of flag

View File

@ -495,6 +495,7 @@ public:
void stackMoved(int number, int destHex, bool endMoving, int distance); //stack with id number moved to destHex
void stacksAreAttacked(std::vector<SStackAttackedInfo> attackedInfos); //called when a certain amount of stacks has been attacked
void stackAttacking(int ID, int dest, int attackedID); //called when stack with id ID is attacking something on hex dest
void newRoundFirst( int round );
void newRound(int number); //caled when round is ended; number is the number of round
void hexLclicked(int whichOne); //hex only call-in
void stackIsShooting(int ID, int dest, int attackedID); //called when stack with id ID is shooting to hex dest

View File

@ -534,7 +534,7 @@ void CPlayerInterface::battlefieldPrepared(int battlefieldType, std::vector<CObs
{
}
void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks)
void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom)
{
if(LOCPLINT != this)
{ //another local interface should do this
@ -550,6 +550,26 @@ void CPlayerInterface::battleStacksHealedRes(const std::vector<std::pair<ui32, u
battleInt->creAnims[healed->ID]->setType(2);
}
}
if (lifeDrain)
{
const CStack *attacker = cb->battleGetStackByID(healedStacks[0].first, false);
const CStack *defender = cb->battleGetStackByID(lifeDrainFrom, false);
if (attacker)
{
battleInt->displayEffect(50, attacker->position);
}
//print info about life drain
int textOff = 0;
if (attacker->count > 1)
{
textOff += 1;
}
char textBuf[1000];
sprintf(textBuf, CGI->generaltexth->allTexts[361 + textOff].c_str(), attacker->getCreature()->nameSing.c_str(),
healedStacks[0].second, defender->getCreature()->namePl.c_str());
battleInt->console->addText(textBuf);
}
}
void CPlayerInterface::battleNewStackAppeared(int stackID)
@ -740,6 +760,7 @@ void CPlayerInterface::battleStacksAttacked(std::vector<BattleStackAttacked> & b
}
SStackAttackedInfo to_put = {i->stackAttacked, i->damageAmount, i->killedAmount, i->attackerID, LOCPLINT->curAction->actionType==7, i->killed()};
arg.push_back(to_put);
}
if(bsa.begin()->isEffect() && bsa.begin()->effect == 12) //for armageddon - I hope this condition is enough
@ -1909,4 +1930,15 @@ void CPlayerInterface::updateInfo(const CGObjectInstance * specific)
adventureInt->infoBar.updateSelection(specific);
// if (adventureInt->selection == specific)
// adventureInt->infoBar.showAll(screen);
}
}
void CPlayerInterface::battleNewRoundFirst( int round )
{
if(LOCPLINT != this)
{ //another local interface should do this
return;
}
boost::unique_lock<boost::recursive_mutex> un(*pim);
battleInt->newRoundFirst(round);
}

View File

@ -184,6 +184,7 @@ public:
void battleAttack(BattleAttack *ba); //stack performs attack
void battleEnd(BattleResult *br); //end of battle
//void battleResultQuited();
void battleNewRoundFirst(int round); //called at the beginning of each turn before changes are applied; used for HP regen handling
void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
void battleStackMoved(int ID, int dest, int distance, bool end);
void battleSpellCast(SpellCast *sc);
@ -191,7 +192,7 @@ public:
void battleStacksAttacked(std::vector<BattleStackAttacked> & bsa);
void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks); //called when stacks are healed / resurrected
void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, si32 lifeDrainFrom); //called when stacks are healed / resurrected
void battleNewStackAppeared(int stackID); //not called at the beginning of a battle or by resurrection; called eg. when elemental is summoned
void battleObstaclesRemoved(const std::set<si32> & removedObstacles); //called when a certain set of obstacles is removed from batlefield; IDs of them are given
void battleCatapultAttacked(const CatapultAttack & ca); //called when catapult makes an attack

View File

@ -436,6 +436,14 @@ void BattleStart::applyCl( CClient *cl )
cl->playerint[info->side2]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 1);
}
void BattleNextRound::applyFirstCl(CClient *cl)
{
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side1]->battleNewRoundFirst(round);
if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side2]->battleNewRoundFirst(round);
}
void BattleNextRound::applyCl( CClient *cl )
{
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())
@ -489,6 +497,13 @@ void BattleAttack::applyFirstCl( CClient *cl )
cl->playerint[GS(cl)->curB->side1]->battleAttack(this);
if(cl->playerint.find(GS(cl)->curB->side2) != cl->playerint.end())
cl->playerint[GS(cl)->curB->side2]->battleAttack(this);
for (int g=0; g<bsa.size(); ++g)
{
for (int z=0; z<bsa[g].healedStacks.size(); ++z)
{
bsa[g].healedStacks[z].applyCl(cl);
}
}
}
void BattleAttack::applyCl( CClient *cl )
@ -555,8 +570,8 @@ void StacksHealedOrResurrected::applyCl( CClient *cl )
{
shiftedHealed.push_back(std::make_pair(healedStacks[v].stackID, healedStacks[v].healedHP));
}
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1, battleStacksHealedRes, shiftedHealed);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleStacksHealedRes, shiftedHealed);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side1, battleStacksHealedRes, shiftedHealed, lifeDrain, drainedFrom);
INTERFACE_CALL_IF_PRESENT(GS(cl)->curB->side2, battleStacksHealedRes, shiftedHealed, lifeDrain, drainedFrom);
}
void ObstaclesRemoved::applyCl( CClient *cl )

View File

@ -2441,11 +2441,11 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
float dec = 0.025f * (-attackDefenceDifference);
if(dec > 0.7f)
{
multBonus *= 1.0f - dec;
multBonus *= 0.3f; //1.0 - 0.7
}
else
{
multBonus *= dec;
multBonus *= 1.0f - dec;
}
}
else //increasing dmg

View File

@ -860,9 +860,9 @@ struct BattleStart : public CPackForClient//3000
struct BattleNextRound : public CPackForClient//3001
{
BattleNextRound(){type = 3001;};
void applyFirstCl(CClient *cl);
void applyCl(CClient *cl);
DLL_EXPORT void applyGs(CGameState *gs);
DLL_EXPORT void applyGs( CGameState *gs );
si32 round;
template <typename Handler> void serialize(Handler &h, const int version)
@ -916,6 +916,34 @@ struct BattleStackMoved : public CPackForClient//3004
}
};
struct StacksHealedOrResurrected : public CPackForClient //3013
{
StacksHealedOrResurrected(){type = 3013;}
DLL_EXPORT void applyGs(CGameState *gs);
void applyCl(CClient *cl);
struct HealInfo
{
ui32 stackID;
ui32 healedHP;
ui8 lowLevelResurrection; //in case this stack is resurrected by this heal, it will be marked as SUMMONED
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackID & healedHP & lowLevelResurrection;
}
};
std::vector<HealInfo> healedStacks;
ui8 lifeDrain; //if true, this heal is an effect of life drain
si32 drainedFrom; //if life drain - then stack life was drain from
template <typename Handler> void serialize(Handler &h, const int version)
{
h & healedStacks & lifeDrain & drainedFrom;
}
};
struct BattleStackAttacked : public CPackForClient//3005
{
BattleStackAttacked(){flags = 0; type = 3005;};
@ -926,18 +954,24 @@ struct BattleStackAttacked : public CPackForClient//3005
ui32 newAmount, newHP, killedAmount, damageAmount;
ui8 flags; //1 - is stack killed; 2 - is there special effect to be shown;
ui32 effect; //set only if flag 2 is present
std::vector<StacksHealedOrResurrected> healedStacks; //used when life drain
bool killed() const//if target stack was killed
{
return flags & 1;
}
bool isEffect() const//if target stack was killed
bool isEffect() const//if stack has been attacked by a spell
{
return flags & 2;
}
bool lifeDrain() const //if this attack involves life drain effect
{
return healedStacks.size() > 0;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackAttacked & attackerID & newAmount & newHP & flags & killedAmount & damageAmount & effect;
h & stackAttacked & attackerID & newAmount & newHP & flags & killedAmount & damageAmount & effect
& healedStacks;
}
bool operator<(const BattleStackAttacked &b) const
{
@ -1067,32 +1101,6 @@ struct BattleResultsApplied : public CPackForClient //3012
}
};
struct StacksHealedOrResurrected : public CPackForClient //3013
{
StacksHealedOrResurrected(){type = 3013;}
DLL_EXPORT void applyGs(CGameState *gs);
void applyCl(CClient *cl);
struct HealInfo
{
ui32 stackID;
ui32 healedHP;
ui8 lowLevelResurrection; //in case this stack is resurrected by this heal, it will be marked as SUMMONED
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stackID & healedHP & lowLevelResurrection;
}
};
std::vector<HealInfo> healedStacks;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & healedStacks;
}
};
struct ObstaclesRemoved : public CPackForClient //3014
{
ObstaclesRemoved(){type = 3014;}

View File

@ -770,6 +770,12 @@ DLL_EXPORT void BattleStackAttacked::applyGs( CGameState *gs )
at->firstHPleft = newHP;
if(killed())
at->state -= ALIVE;
//life drain handling
for (int g=0; g<healedStacks.size(); ++g)
{
healedStacks[g].applyGs(gs);
}
}
DLL_EXPORT void BattleAttack::applyGs( CGameState *gs )
@ -1121,7 +1127,7 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
//applying changes
bool resurrected = !changedStack->alive(); //indicates if stack is resurrected or just healed
if(!changedStack->alive())
if(resurrected)
{
changedStack->state.insert(ALIVE);
if(healedStacks[g].lowLevelResurrection)

View File

@ -654,6 +654,28 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
int dmg = bsa->damageAmount;
prepareAttacked(*bsa, def);
//life drain handling
if (att->hasBonusOfType(Bonus::LIFE_DRAIN))
{
StacksHealedOrResurrected shi;
shi.lifeDrain = true;
shi.drainedFrom = def->ID;
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)
{
bsa->healedStacks.push_back(shi);
}
}
else
{
}
//fire shield handling
if ( !bat.shot() && def->hasBonusOfType(Bonus::FIRE_SHIELD) && !bsa->killed() )
{
@ -667,6 +689,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
bsa->damageAmount = (dmg * def->valOfBonuses(Bonus::FIRE_SHIELD)) / 100;
prepareAttacked(*bsa, att);
}
}
void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
{
@ -3290,6 +3313,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
else
{
StacksHealedOrResurrected shr;
shr.lifeDrain = false;
StacksHealedOrResurrected::HealInfo hi;
hi.healedHP = healed;
@ -3647,6 +3671,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
case 39: //animate dead
{
StacksHealedOrResurrected shr;
shr.lifeDrain = false;
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
{
if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell