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:
parent
399f58f1af
commit
e60c6785a4
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user