1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

* Necromancy implemented. Not sure if they client/server communication is right, but it works.

* Cloak of the Undead King implemented as well.
This commit is contained in:
OnionKnight 2009-08-31 22:04:00 +00:00
parent 399f58f1af
commit e60c6785a4
3 changed files with 100 additions and 2 deletions

View File

@ -1013,6 +1013,79 @@ bool CGHeroInstance::canCastThisSpell(const CSpell * spell) const
return false;
}
/**
* Calculates what creatures and how many to be raised from a battle.
* @param battleResult The results of the battle.
* @return Returns a pair with the first value indicating the ID of the creature
* type and second value the amount. Both values are returned as -1 if necromancy
* could not be applied.
*/
std::pair<ui32, si32> CGHeroInstance::calculateNecromancy (BattleResult &battleResult) const
{
const ui8 necromancyLevel = getSecSkillLevel(12);
// Hero knows necromancy.
if (necromancyLevel > 0) {
double necromancySkill = necromancyLevel*0.1
+ valOfBonuses(HeroBonus::SECONDARY_SKILL_PREMY, 12)/100.0;
const std::set<std::pair<ui32, si32> > &casualties = battleResult.casualties[!battleResult.winner];
ui32 raisedUnits = 0;
// Get lost enemy hit points convertible to units.
for (std::set<std::pair<ui32, si32> >::const_iterator it = casualties.begin(); it != casualties.end(); it++)
raisedUnits += VLC->creh->creatures[it->first].hitPoints*it->second;
raisedUnits *= necromancySkill;
// Figure out what to raise and how many.
const ui32 creatureTypes[] = {56, 58, 60, 64}; // IDs for Skeletons, Walking Dead, Wights and Liches respectively.
const bool improvedNecromancy = hasBonusOfType(HeroBonus::IMPROVED_NECROMANCY);
CCreature *raisedUnitType = &VLC->creh->creatures[creatureTypes[improvedNecromancy ? necromancyLevel : 0]];
raisedUnits /= raisedUnitType->hitPoints;
// Make room for new units.
int slot = army.getSlotFor(raisedUnitType->idNumber);
if (slot == -1) {
// If there's no room for unit, try it's upgraded version 2/3rds the size.
raisedUnitType = &VLC->creh->creatures[*raisedUnitType->upgrades.begin()];
raisedUnits = (raisedUnits*2)/3;
slot = army.getSlotFor(raisedUnitType->idNumber);
}
if (raisedUnits <= 0)
raisedUnits = 1;
return std::pair<ui32, si32>(raisedUnitType->idNumber, raisedUnits);
}
return std::pair<ui32, si32>(-1, -1);
}
/**
* Show the necromancy dialog with information about units raised.
* @param raisedStack Pair where the first element represents ID of the raised creature
* and the second element the amount.
*/
void CGHeroInstance::showNecromancyDialog (std::pair<ui32, si32> raisedStack) const
{
const CCreature &unitType = VLC->creh->creatures[raisedStack.first];
InfoWindow iw;
iw.soundID = soundBase::GENIE;
iw.player = tempOwner;
iw.components.push_back(Component(3, unitType.idNumber, raisedStack.second, 0));
if (raisedStack.second > 1) { // Practicing the dark arts of necromancy, ... (plural)
iw.text.addTxt(MetaString::GENERAL_TXT, 145);
iw.text.addReplacement(raisedStack.second);
iw.text.addReplacement(MetaString::CRE_PL_NAMES, unitType.idNumber);
} else { // Practicing the dark arts of necromancy, ... (singular)
iw.text.addTxt(MetaString::GENERAL_TXT, 146);
iw.text.addReplacement(MetaString::CRE_SING_NAMES, unitType.idNumber);
}
cb->showInfoDialog(&iw);
}
int3 CGHeroInstance::getSightCenter() const
{
return getPosition(false);

View File

@ -293,6 +293,8 @@ public:
int getTotalStrength() const;
ui8 getSpellSchoolLevel(const CSpell * spell) const; //returns level on which given spell would be cast by this hero
bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
std::pair<ui32, si32> calculateNecromancy (BattleResult &battleResult) const;
void showNecromancyDialog (std::pair<ui32, si32> raisedStack) const;
//////////////////////////////////////////////////////////////////////////

View File

@ -450,9 +450,32 @@ askInterfaceForMove:
if(cb)
cb(battleResult.data);
delete battleResult.data;
sendAndApply(&resultsApplied);
// Necromancy if applicable.
const CGHeroInstance *winnerHero = battleResult.data->winner != 0 ? hero2 : hero1;
if (winnerHero) {
std::pair<ui32, si32> raisedStack = winnerHero->calculateNecromancy(*battleResult.data);
// Give raised units to winner and show dialog, if any were raised.
if (raisedStack.first != -1) {
int slot = winnerHero->army.getSlotFor(raisedStack.first);
if (slot != -1) {
SetGarrisons sg;
sg.garrs[winnerHero->id] = winnerHero->army;
if (vstd::contains(winnerHero->army.slots, slot)) // Add to existing stack.
sg.garrs[winnerHero->id].slots[slot].second += raisedStack.second;
else // Create a new stack.
sg.garrs[winnerHero->id].slots[slot] = raisedStack;
winnerHero->showNecromancyDialog(raisedStack);
sendAndApply(&sg);
}
}
}
delete battleResult.data;
}
void CGameHandler::prepareAttacked(BattleStackAttacked &bsa, CStack *def)