From 515ab7e7c14f7ee1b3acc8e040730b10fc3c076f Mon Sep 17 00:00:00 2001 From: DjWarmonger Date: Fri, 13 May 2011 09:02:16 +0000 Subject: [PATCH] Support for Acid Breath (both effects are now separate). Minor fixes. --- client/CBattleInterface.cpp | 2 ++ client/CCreatureWindow.cpp | 13 ++++++++----- config/cr_abils.txt | 26 +++++++++++++------------ lib/BattleState.cpp | 8 +++++++- lib/CSpellHandler.cpp | 39 +++++++++++++++++++------------------ lib/HeroBonus.cpp | 2 ++ lib/HeroBonus.h | 3 ++- server/CGameHandler.cpp | 39 +++++++++++++++++++++++++++++++++---- 8 files changed, 90 insertions(+), 42 deletions(-) diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index 06c957e3b..78d52a701 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -2935,6 +2935,8 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc ) else text = ""; break; + case 81: + break; //handled as hero spell - display damage default: boost::algorithm::replace_first(text, "%s", "Creature"); //TODO: better fix } diff --git a/client/CCreatureWindow.cpp b/client/CCreatureWindow.cpp index 765414e45..ed7053019 100644 --- a/client/CCreatureWindow.cpp +++ b/client/CCreatureWindow.cpp @@ -240,9 +240,12 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode * std::vector spells = battleStack->activeSpells(); BOOST_FOREACH(si32 effect, spells) { - blitAt(graphics->spellEffectsPics->ourImages[effect + 1].bitmap, 20 + 52 * printed, 184, *bitmap); - if (++printed >= 10) //we can fit only 10 effects - break; + if (effect < graphics->spellEffectsPics->ourImages.size()) //not all effects have graphics (for eg. Acid Breath) + { + blitAt(graphics->spellEffectsPics->ourImages[effect + 1].bitmap, 20 + 52 * printed, 184, *bitmap); + if (++printed >= 10) //we can fit only 10 effects + break; + } } //print current health printLine (5, CGI->generaltexth->allTexts[200], battleStack->firstHPleft); @@ -314,8 +317,8 @@ void CCreatureWindow::showAll(SDL_Surface * to) printTo(count, 117, 174, FONT_SMALL, tytulowy,*bitmap); printAtMiddle(c->namePl, 180, 30, FONT_SMALL, tytulowy,*bitmap); //creature name - printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK)); - printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE)); + printLine(0, CGI->generaltexth->primarySkillNames[0], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), stackNode->Attack()); + printLine(1, CGI->generaltexth->primarySkillNames[1], c->valOfBonuses(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE), stackNode->Defense()); //if(c->shots) // printLine(2, CGI->generaltexth->allTexts[198], c->shots); if(stackNode->valOfBonuses(Bonus::SHOTS)) diff --git a/config/cr_abils.txt b/config/cr_abils.txt index e5c2c04bc..edfa2f3e9 100644 --- a/config/cr_abils.txt +++ b/config/cr_abils.txt @@ -179,22 +179,24 @@ + 133 DRAGON_NATURE 0 0 0 //crystal dragon is a dragon + 134 DRAGON_NATURE 0 0 0 //faerie dragon is a dragon + 135 DRAGON_NATURE 0 0 0 //rust dragon is a dragon ++ 135 ACID_BREATH 25 0 20 //20% chance to do 25 damage ++ 135 SPELL_AFTER_ATTACK 100 80 0 //always reduce defense + 136 NO_OBSTACLES_PENALTY 0 0 0 //Enchanter + 137 NO_DISTANCE_PENALTY 0 0 0 //Sharpshooter + 137 NO_OBSTACLES_PENALTY 0 0 0 + 140 DOUBLE_WIDE 0 0 0 //boar should be treated as double-wide -+ 142 DOUBLE_WIDE 0 0 0 //nomads should be treated as double-wide -+ 144 FULL_HP_REGENERATION 0 0 0 //troll -+ 147 HEALER 0 0 0 //first aid tent can heal -+ 148 NOT_ACTIVE 0 0 0 //Ammo Cart -+ 149 SHOOTER 0 0 0 //arrow turret ++ 142 DOUBLE_WIDE 0 0 0 //nomads should be treated as double-wide //first aid tent can heal ++ 144 FULL_HP_REGENERATION 0 0 0 //troll //Ammo Cart ++ 147 HEALER 0 0 0 //arrow turret ++ 148 NOT_ACTIVE 0 0 0 ++ 149 SHOOTER 0 0 0 + 151 DRAGON_NATURE 0 0 0 //diamond dragon is a dragon -+ 154 DRAGON_NATURE 0 0 0 //blood dragon is a dragon -+ 155 DRAGON_NATURE 0 0 0 //darkness dragon is a dragon -+ 168 FLYING 0 0 0 //Gorynyches fly -- 46 FLYING //hell hound doesn't fly -- 47 FLYING //cerberus doesn't fly -- 120 DOUBLE_WIDE //psychic elemental -- 121 DOUBLE_WIDE //magic elemental ++ 154 DRAGON_NATURE 0 0 0 //blood dragon is a dragon //Gorynyches fly ++ 155 DRAGON_NATURE 0 0 0 //darkness dragon is a dragon //hell hound doesn't fly ++ 168 FLYING 0 0 0 //cerberus doesn't fly +- 46 FLYING //psychic elemental +- 47 FLYING //magic elemental +- 120 DOUBLE_WIDE +- 121 DOUBLE_WIDE - 157 SHOOTER //Hell Hydra certainly does not shoot 0 diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 1acbfab50..ac477af57 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -1792,7 +1792,7 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance } if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) || - ( immunities.size() > 0 && immunities.totalValue() >= spell->level)) //many creature abilities have level equal to 0 by default, fixed in config\spell_levels + ( immunities.size() > 0 && immunities.totalValue() >= spell->level && spell->level)) { return SpellCasting::STACK_IMMUNE_TO_SPELL; } @@ -2167,6 +2167,12 @@ void CStack::stackEffectToFeature(std::vector & sf, const Bonus & sse) sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -50, 3, Bonus::PERCENT_TO_ALL)); sf.back().sid = sse.sid; break; + case 80: //Acid Breath + sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -3, 1)); + sf.back().sid = sse.sid; + sf.back().duration = Bonus::PERMANENT; + sf.back().valType = Bonus::ADDITIVE_VALUE; + break; } } diff --git a/lib/CSpellHandler.cpp b/lib/CSpellHandler.cpp index 46a33497c..b57bf9dcc 100644 --- a/lib/CSpellHandler.cpp +++ b/lib/CSpellHandler.cpp @@ -322,23 +322,24 @@ void CSpellHandler::loadSpells() } } ast.close(); - ast.open(DATA_DIR "/config/spell_levels.txt", std::ios::binary); - if(!ast.is_open()) - { - tlog1<<"lack of config/spell_levels.txt file!"<>spellID; - int buf; - while(spellID != -1) - { - ast >> buf; - spells[spellID]->level = buf; - ast>>spellID; - } - } - ast.close(); + //ast.open(DATA_DIR "/config/spell_levels.txt", std::ios::binary); + //if(!ast.is_open()) + //{ + // tlog1<<"lack of config/spell_levels.txt file!"<>spellID; + // int buf; + // while(spellID != -1) + // { + // ast >> buf; + // spells[spellID]->level = buf; + // ast>>spellID; + // } + //} + //ast.close(); + spells.push_back(spells[80]); //clone Acid Breath attributes for Acid Breath damage effect } diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 6bf9d804a..ba8ec9484 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -269,6 +269,7 @@ si32 IBonusBearer::Attack() const { ret += frenzyPower * Defense(false); } + amax(ret, 0); return ret; } @@ -281,6 +282,7 @@ si32 IBonusBearer::Defense(bool withFrenzy /*= true*/) const { return 0; } + amax(ret, 0); return ret; } diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 1b5c713f6..6f58c9ac6 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -159,7 +159,8 @@ namespace PrimarySkill BONUS_NAME(SHOTS)\ BONUS_NAME(DEATH_STARE) /*subtype 0 - gorgon, 1 - commander*/\ BONUS_NAME(POISON) /*val - max health penalty from poison possible*/\ - BONUS_NAME(BIND_EFFECT) /*doesn't do anything particular, works as a marker)*/ + BONUS_NAME(BIND_EFFECT) /*doesn't do anything particular, works as a marker)*/\ + BONUS_NAME(ACID_BREATH) /*additional val damage per creature after attack, additional info - chance in percent*/ /// Struct for handling bonuses of several types. Can be transfered to any hero struct DLL_EXPORT Bonus diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index a611d3c42..dd2e193ed 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -3397,10 +3397,11 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio continue; sc.dmgToDisplay += gs->curB->calculateSpellDmg(spell, caster, *it, spellLvl, usedSpellPower); } - if (spellID == 79) // Death stare + if (spellID == 79 || spellID == 81) // Death stare or Acid Breath { sc.dmgToDisplay = usedSpellPower; - amin(sc.dmgToDisplay, (*attackedCres.begin())->count); //stack is already reduced after attack + if (spellID == 79) + amin(sc.dmgToDisplay, (*attackedCres.begin())->count); //stack is already reduced after attack } //applying effects @@ -3474,6 +3475,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio case 73: //Disease case 74: //Paralyze case 75: //Aging + case 80: //Acid Breath defense reduction { SetStackEffect sse; Bonus pseudoBonus; @@ -3529,7 +3531,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio } if (caster && caster->hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, spellID)) //TODO: better handling of bonus percentages { - int damagePercent = caster->level * caster->valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / tier; + int damagePercent = caster->level * caster->valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, spellID) / tier; Bonus specialBonus = CStack::featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, pseudoBonus.turnsRemain); specialBonus.valType = Bonus::PERCENT_TO_ALL; specialBonus.sid = spellID; @@ -3617,10 +3619,27 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio sendAndApply(&si); } break; + case 81: //Acid breath damage - new effect, separate from acid breath defense reduction + { + StacksInjured si; + for(std::set::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it) //no immunities + { + BattleStackAttacked bsa; + bsa.flags |= BattleStackAttacked::EFFECT; + bsa.effect = VLC->spellh->spells[80]->mainEffectAnim; //use acid breath + bsa.damageAmount = usedSpellPower; //damage times the number of attackers + bsa.stackAttacked = (*it)->ID; + bsa.attackerID = -1; + (*it)->prepareAttacked(bsa); + si.stacks.push_back(bsa); + } + if(!si.stacks.empty()) + sendAndApply(&si); + } + break; } sendAndApply(&sc); - } bool CGameHandler::makeCustomAction( BattleAction &ba ) @@ -4286,6 +4305,18 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat ) !attacker->attackerOwned, attacker->owner, NULL, NULL, staredCreatures, SpellCasting::AFTER_ATTACK_CASTING); } } + int acidDamage = 0; + BOOST_FOREACH(const Bonus *b, attacker->getBonuses(Selector::type(Bonus::ACID_BREATH))) + { + if (b->additionalInfo > rand()%100) + acidDamage += b->val; + } + if (acidDamage) + { + handleSpellCasting(81, 0, gs->curB->getStack(bat.bsa[0].stackAttacked)->position, + !attacker->attackerOwned, attacker->owner, NULL, NULL, + acidDamage * attacker->count, SpellCasting::AFTER_ATTACK_CASTING); + } } bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &pos)