|
@@ -10,6 +10,7 @@
|
|
|
#include "CGeneralTextHandler.h"
|
|
|
#include "CSpellHandler.h"
|
|
|
#include "CHeroHandler.h"
|
|
|
+#include "IBonusTypeHandler.h"
|
|
|
|
|
|
/*
|
|
|
* CCreatureSet.cpp, part of VCMI engine
|
|
@@ -561,341 +562,20 @@ void CStackInstance::setType(const CCreature *c)
|
|
|
}
|
|
|
std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
|
|
{
|
|
|
- std::map<Bonus::BonusType, std::pair<std::string, std::string> >::iterator it = VLC->creh->stackBonuses.find(bonus->type);
|
|
|
- if (it != VLC->creh->stackBonuses.end())
|
|
|
+ if(Bonus::MAGIC_RESISTANCE == bonus->type)
|
|
|
{
|
|
|
- std::string text;
|
|
|
- if (description) //long ability description
|
|
|
- {
|
|
|
- text = it->second.second;
|
|
|
- switch (bonus->type)
|
|
|
- {
|
|
|
- //no additional modifiers needed
|
|
|
- case Bonus::FLYING:
|
|
|
- case Bonus::UNLIMITED_RETALIATIONS:
|
|
|
- case Bonus::SHOOTER:
|
|
|
- case Bonus::FREE_SHOOTING:
|
|
|
- case Bonus::NO_MELEE_PENALTY:
|
|
|
- case Bonus::NO_DISTANCE_PENALTY:
|
|
|
- case Bonus::NO_WALL_PENALTY:
|
|
|
- case Bonus::JOUSTING: //TODO: percent bonus?
|
|
|
- case Bonus::RETURN_AFTER_STRIKE:
|
|
|
- case Bonus::BLOCKS_RETALIATION:
|
|
|
- case Bonus::TWO_HEX_ATTACK_BREATH:
|
|
|
- case Bonus::THREE_HEADED_ATTACK:
|
|
|
- case Bonus::ATTACKS_ALL_ADJACENT:
|
|
|
- case Bonus::ADDITIONAL_ATTACK: //TODO: what with more than one attack? Axe of Ferocity for example
|
|
|
- case Bonus::FULL_HP_REGENERATION:
|
|
|
- case Bonus::MANA_DRAIN:
|
|
|
- case Bonus::LIFE_DRAIN:
|
|
|
- case Bonus::REBIRTH:
|
|
|
- case Bonus::SELF_MORALE:
|
|
|
- case Bonus::SELF_LUCK:
|
|
|
- case Bonus::FEAR:
|
|
|
- case Bonus::FEARLESS:
|
|
|
- case Bonus::CHARGE_IMMUNITY:
|
|
|
- case Bonus::HEALER:
|
|
|
- case Bonus::CATAPULT:
|
|
|
- case Bonus::DRAGON_NATURE:
|
|
|
- case Bonus::NON_LIVING:
|
|
|
- case Bonus::UNDEAD:
|
|
|
- case Bonus::FIRE_IMMUNITY:
|
|
|
- case Bonus::WATER_IMMUNITY:
|
|
|
- case Bonus::AIR_IMMUNITY:
|
|
|
- case Bonus::EARTH_IMMUNITY:
|
|
|
- case Bonus::RECEPTIVE:
|
|
|
- case Bonus::DIRECT_DAMAGE_IMMUNITY:
|
|
|
- break;
|
|
|
- //One numeric value. magic resistance handled separately
|
|
|
- case Bonus::SPELL_RESISTANCE_AURA:
|
|
|
- case Bonus::SPELL_DAMAGE_REDUCTION:
|
|
|
- case Bonus::LEVEL_SPELL_IMMUNITY:
|
|
|
- case Bonus::HP_REGENERATION:
|
|
|
- case Bonus::ADDITIONAL_RETALIATION:
|
|
|
- case Bonus::DEFENSIVE_STANCE:
|
|
|
- case Bonus::DOUBLE_DAMAGE_CHANCE:
|
|
|
- case Bonus::DARKNESS: //Darkness Dragons any1?
|
|
|
- boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
|
|
|
- break;
|
|
|
- //Complex descriptions
|
|
|
- //case Bonus::SECONDARY_SKILL_PREMY: //only if there's no simple MR
|
|
|
- // if (bonus->subtype == CGHeroInstance::RESISTANCE)
|
|
|
- // {
|
|
|
- // if (!hasBonusOfType(Bonus::MAGIC_RESISTANCE))
|
|
|
- // boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>( magicResistance() ));
|
|
|
- // }
|
|
|
- // break;
|
|
|
- //case Bonus::MAGIC_RESISTANCE:
|
|
|
- // boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>( magicResistance() ));
|
|
|
- // break;
|
|
|
- case Bonus::HATE:
|
|
|
- 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->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);
|
|
|
- break;
|
|
|
- }
|
|
|
- case Bonus::SPELL_LIKE_ATTACK:
|
|
|
- {
|
|
|
- boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
|
|
|
- break;
|
|
|
- }
|
|
|
- default:
|
|
|
- {}//TODO: allow custom bonus types... someday, somehow
|
|
|
- }
|
|
|
- }
|
|
|
- else //short name
|
|
|
- {
|
|
|
- text = it->second.first;
|
|
|
- switch (bonus->type)
|
|
|
- {
|
|
|
- case Bonus::MANA_CHANNELING:
|
|
|
- case Bonus::MAGIC_MIRROR:
|
|
|
- case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
|
|
|
- case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
|
|
|
- case Bonus::ENEMY_DEFENCE_REDUCTION:
|
|
|
- case Bonus::REBIRTH:
|
|
|
- case Bonus::DEATH_STARE:
|
|
|
- case Bonus::LIFE_DRAIN:
|
|
|
- case Bonus::FIRE_SHIELD:
|
|
|
- boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(valOfBonuses(Selector::typeSubtype(bonus->type, bonus->subtype))));
|
|
|
- break;
|
|
|
- case Bonus::HATE:
|
|
|
- case Bonus::DAEMON_SUMMONING:
|
|
|
- boost::algorithm::replace_first(text, "%s", VLC->creh->creatures[bonus->subtype]->namePl);
|
|
|
- break;
|
|
|
- case Bonus::LEVEL_SPELL_IMMUNITY:
|
|
|
- boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bonus->val));
|
|
|
- break;
|
|
|
- case Bonus::SPELL_AFTER_ATTACK:
|
|
|
- case Bonus::SPELL_BEFORE_ATTACK:
|
|
|
- case Bonus::SPELL_IMMUNITY:
|
|
|
- case Bonus::SPELLCASTER:
|
|
|
- case Bonus::ENCHANTER:
|
|
|
- case Bonus::ENCHANTED:
|
|
|
- boost::algorithm::replace_first(text, "%s", VLC->spellh->spells[bonus->subtype]->name);
|
|
|
- break;
|
|
|
- case Bonus::MAGIC_RESISTANCE:
|
|
|
- text = ""; //handled separately
|
|
|
- break;
|
|
|
- //case Bonus::SECONDARY_SKILL_PREMY:
|
|
|
- // if (bonus->subtype != CGHeroInstance::RESISTANCE || hasBonusOfType(Bonus::MAGIC_RESISTANCE)) //handle it there
|
|
|
- // text = "";
|
|
|
- // break;
|
|
|
- }
|
|
|
- }
|
|
|
- return text;
|
|
|
+ return "";
|
|
|
}
|
|
|
else
|
|
|
- return "";
|
|
|
+ {
|
|
|
+ return VLC->getBth()->bonusToString(bonus, this, description);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
|
|
{
|
|
|
- std::string fileName;
|
|
|
- bool fullPath = false;
|
|
|
- switch (bonus->type)
|
|
|
- {
|
|
|
- //"E_ALIVE.bmp"
|
|
|
- //"E_ART.bmp"
|
|
|
- case Bonus::ENCHANTED:
|
|
|
- fileName = "E_BLESS.bmp"; break;
|
|
|
- //"E_BLOCK.bmp"
|
|
|
- //"E_BLOCK1.bmp"
|
|
|
- //"E_BLOCK2.bmp"
|
|
|
- case Bonus::TWO_HEX_ATTACK_BREATH:
|
|
|
- fileName = "E_BREATH.bmp"; break;
|
|
|
- case Bonus::SPELL_AFTER_ATTACK:
|
|
|
- fileName = "E_CAST.bmp"; break;
|
|
|
- case Bonus::ENCHANTER:
|
|
|
- fileName = "E_CAST1.bmp"; break;
|
|
|
- case Bonus::RANDOM_SPELLCASTER:
|
|
|
- fileName = "RandomBoost.bmp"; break;
|
|
|
- case Bonus::SPELL_BEFORE_ATTACK:
|
|
|
- fileName ="E_CAST2.bmp"; break;
|
|
|
- case Bonus::SPELLCASTER:
|
|
|
- fileName = "E_CASTER.bmp"; break;
|
|
|
- case Bonus::JOUSTING:
|
|
|
- fileName = "E_CHAMP.bmp"; break;
|
|
|
- case Bonus::DOUBLE_DAMAGE_CHANCE:
|
|
|
- fileName = "E_DBLOW.bmp"; break;
|
|
|
- case Bonus::DEATH_STARE:
|
|
|
- fileName = "E_DEATH.bmp"; break;
|
|
|
- case Bonus::DEFENSIVE_STANCE:
|
|
|
- fileName = "E_DEFBON.bmp"; break;
|
|
|
- case Bonus::NO_DISTANCE_PENALTY:
|
|
|
- fileName = "E_DIST.bmp"; break;
|
|
|
- case Bonus::ADDITIONAL_ATTACK:
|
|
|
- fileName = "E_DOUBLE.bmp"; break;
|
|
|
- case Bonus::DRAGON_NATURE:
|
|
|
- fileName = "E_DRAGON.bmp"; break;
|
|
|
- case Bonus::MAGIC_RESISTANCE:
|
|
|
- fileName = "E_DWARF.bmp"; break;
|
|
|
- case Bonus::SECONDARY_SKILL_PREMY:
|
|
|
- if (bonus->subtype == SecondarySkill::RESISTANCE)
|
|
|
- {
|
|
|
- fileName = "E_DWARF.bmp";
|
|
|
- }
|
|
|
- break;
|
|
|
- case Bonus::FEAR:
|
|
|
- fileName = "E_FEAR.bmp"; break;
|
|
|
- case Bonus::FEARLESS:
|
|
|
- fileName = "E_FEARL.bmp"; break;
|
|
|
- case Bonus::FLYING:
|
|
|
- fileName = "E_FLY.bmp"; break;
|
|
|
- case Bonus::SPELL_DAMAGE_REDUCTION:
|
|
|
- fileName = "E_GOLEM.bmp"; break;
|
|
|
- case Bonus::RETURN_AFTER_STRIKE:
|
|
|
- fileName = "E_HARPY.bmp"; break;
|
|
|
- case Bonus::HATE:
|
|
|
- fileName = "E_HATE.bmp"; break;
|
|
|
- case Bonus::KING1:
|
|
|
- fileName = "E_KING1.bmp"; break;
|
|
|
- case Bonus::KING2:
|
|
|
- fileName = "E_KING2.bmp"; break;
|
|
|
- case Bonus::KING3:
|
|
|
- fileName = "E_KING3.bmp"; break;
|
|
|
- case Bonus::CHANGES_SPELL_COST_FOR_ALLY:
|
|
|
- fileName = "E_MANA.bmp"; break;
|
|
|
- case Bonus::CHANGES_SPELL_COST_FOR_ENEMY:
|
|
|
- fileName = "MagicDamper.bpm"; break;
|
|
|
- case Bonus::NO_MELEE_PENALTY:
|
|
|
- fileName = "E_MELEE.bmp"; break;
|
|
|
- case Bonus::MIND_IMMUNITY:
|
|
|
- fileName = "E_MIND.bmp"; break;
|
|
|
- case Bonus::SELF_MORALE:
|
|
|
- fileName = "E_MINOT.bmp"; break;
|
|
|
- case Bonus::NO_MORALE:
|
|
|
- fileName = "E_MORAL.bmp"; break;
|
|
|
- case Bonus::RECEPTIVE:
|
|
|
- fileName = "E_NOFRIM.bmp"; break;
|
|
|
- case Bonus::NO_WALL_PENALTY:
|
|
|
- fileName = "E_OBST.bmp"; break;
|
|
|
- case Bonus::ENEMY_DEFENCE_REDUCTION:
|
|
|
- fileName = "E_RDEF.bmp"; break;
|
|
|
- case Bonus::REBIRTH:
|
|
|
- fileName = "E_REBIRTH.bmp"; break;
|
|
|
- case Bonus::BLOCKS_RETALIATION:
|
|
|
- fileName = "E_RETAIL.bmp"; break;
|
|
|
- case Bonus::UNLIMITED_RETALIATIONS:
|
|
|
- case Bonus::ADDITIONAL_RETALIATION:
|
|
|
- fileName = "E_RETAIL1.bmp"; break;
|
|
|
- case Bonus::ATTACKS_ALL_ADJACENT:
|
|
|
- fileName = "E_ROUND.bmp"; break;
|
|
|
- //"E_SGNUM.bmp"
|
|
|
- //"E_SGTYPE.bmp"
|
|
|
- case Bonus::SHOOTER:
|
|
|
- fileName = "E_SHOOT.bmp"; break;
|
|
|
- case Bonus::FREE_SHOOTING: //shooter is not blocked by enemy
|
|
|
- fileName = "E_SHOOTA.bmp"; break;
|
|
|
- //"E_SHOOTN.bmp"
|
|
|
- case Bonus::SPELL_IMMUNITY:
|
|
|
- {
|
|
|
- fullPath = true;
|
|
|
- const CSpell * sp = SpellID(bonus->subtype).toSpell();
|
|
|
- fileName = sp->getIconImmune();
|
|
|
- break;
|
|
|
- }
|
|
|
- //"E_SPAWILL.bmp"
|
|
|
- case Bonus::DIRECT_DAMAGE_IMMUNITY:
|
|
|
- fileName = "E_SPDIR.bmp"; break;
|
|
|
- //"E_SPDISB.bmp"
|
|
|
- //"E_SPDISP.bmp"
|
|
|
- //"E_SPEATH.bmp"
|
|
|
- //"E_SPEATH1.bmp"
|
|
|
- case Bonus::FIRE_IMMUNITY:
|
|
|
- switch (bonus->subtype)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- fileName = "E_SPFIRE.bmp"; break; //all
|
|
|
- case 1:
|
|
|
- fileName = "E_SPFIRE1.bmp"; break; //not positive
|
|
|
- case 2:
|
|
|
- fileName = "E_FIRE.bmp"; break; //direct damage
|
|
|
- }
|
|
|
- break;
|
|
|
- case Bonus::WATER_IMMUNITY:
|
|
|
- switch (bonus->subtype)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- fileName = "E_SPWATER.bmp"; break; //all
|
|
|
- case 1:
|
|
|
- fileName = "E_SPWATER1.bmp"; break; //not positive
|
|
|
- case 2:
|
|
|
- fileName = "E_SPCOLD.bmp"; break; //direct damage
|
|
|
- }
|
|
|
- break;
|
|
|
- case Bonus::AIR_IMMUNITY:
|
|
|
- switch (bonus->subtype)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- fileName = "E_SPAIR.bmp"; break; //all
|
|
|
- case 1:
|
|
|
- fileName = "E_SPAIR1.bmp"; break; //not positive
|
|
|
- case 2:
|
|
|
- fileName = "E_LIGHT.bmp"; break;//direct damage
|
|
|
- }
|
|
|
- break;
|
|
|
- case Bonus::EARTH_IMMUNITY:
|
|
|
- switch (bonus->subtype)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- fileName = "E_SPEATH.bmp"; break; //all
|
|
|
- case 1:
|
|
|
- case 2: //no specific icon for direct damage immunity
|
|
|
- fileName = "E_SPEATH1.bmp"; break; //not positive
|
|
|
- }
|
|
|
- break;
|
|
|
- case Bonus::LEVEL_SPELL_IMMUNITY:
|
|
|
- {
|
|
|
- if (vstd::iswithin(bonus->val, 1 , 5))
|
|
|
- {
|
|
|
- fileName = "E_SPLVL" + boost::lexical_cast<std::string>(bonus->val) + ".bmp";
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- //"E_SUMMON.bmp"
|
|
|
- //"E_SUMMON1.bmp"
|
|
|
- //"E_SUMMON2.bmp"
|
|
|
- case Bonus::FULL_HP_REGENERATION:
|
|
|
- case Bonus::HP_REGENERATION:
|
|
|
- fileName = "E_TROLL.bmp"; break;
|
|
|
- case Bonus::UNDEAD:
|
|
|
- fileName = "E_UNDEAD.bmp"; break;
|
|
|
- case Bonus::SPELL_RESISTANCE_AURA:
|
|
|
- fileName = "E_UNIC.bmp"; break;
|
|
|
- case Bonus::THREE_HEADED_ATTACK:
|
|
|
- fileName = "ThreeHeaded.bmp"; break;
|
|
|
- case Bonus::DAEMON_SUMMONING:
|
|
|
- fileName = "RiseDemons.bmp"; break;
|
|
|
- case Bonus::CHARGE_IMMUNITY:
|
|
|
- fileName = "ChargeImmune.bmp"; break;
|
|
|
- case Bonus::HEALER:
|
|
|
- fileName = "Healer.bmp"; break;
|
|
|
- case Bonus::CATAPULT:
|
|
|
- fileName = "Catapult.bmp"; break;
|
|
|
- case Bonus::MANA_CHANNELING:
|
|
|
- fileName = "ManaChannel.bmp"; break;
|
|
|
- case Bonus::MANA_DRAIN:
|
|
|
- fileName = "ManaDrain.bmp"; break;
|
|
|
- case Bonus::LIFE_DRAIN:
|
|
|
- fileName = "DrainLife.bmp"; break;
|
|
|
- case Bonus::FIRE_SHIELD:
|
|
|
- fileName = "FireShield.bmp"; break;
|
|
|
- case Bonus::MAGIC_MIRROR:
|
|
|
- fileName = "MagicMirror.bmp"; break;
|
|
|
- case Bonus::NON_LIVING:
|
|
|
- fileName = "NonLiving.bmp"; break;
|
|
|
- case Bonus::SPELL_LIKE_ATTACK:
|
|
|
- fileName = "SpellLikeAttack.bmp"; break;
|
|
|
- }
|
|
|
- if(!fileName.empty() && !fullPath)
|
|
|
- fileName = "zvs/Lib1.res/" + fileName;
|
|
|
- return fileName;
|
|
|
+ return VLC->getBth()->bonusToGraphics(bonus);
|
|
|
}
|
|
|
|
|
|
void CStackInstance::setArmyObj(const CArmedInstance *ArmyObj)
|