bool CCreatureSet::canBeMergedWith(const CCreatureSet &cs, bool allowMergingStacks) const { if(!allowMergingStacks) { int freeSlots = stacksCount() - GameConstants::ARMY_SIZE; std::set<const CCreature*> cresToAdd; for(TSlots::const_iterator i = cs.stacks.begin(); i != cs.stacks.end(); i++) { SlotID dest = getSlotFor(i->second->type); if(!dest.validSlot() || hasStackAtSlot(dest)) cresToAdd.insert(i->second->type); } return cresToAdd.size() <= freeSlots; } else { CCreatureSet cres; //get types of creatures that need their own slot for(TSlots::const_iterator i = cs.stacks.begin(); i != cs.stacks.end(); i++) cres.addToSlot(i->first, i->second->type->idNumber, 1, true); SlotID j; for(TSlots::const_iterator i = stacks.begin(); i != stacks.end(); i++) { if ((j = cres.getSlotFor(i->second->type)).validSlot()) cres.addToSlot(j, i->second->type->idNumber, 1, true); //merge if possible else return false; //no place found } return true; //all stacks found their slots } }
/** * 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. */ CStackBasicDescriptor CGHeroInstance::calculateNecromancy (const BattleResult &battleResult) const { const ui8 necromancyLevel = getSecSkillLevel(SecondarySkill::NECROMANCY); // Hero knows necromancy or has Necromancer Cloak if (necromancyLevel > 0 || hasBonusOfType(Bonus::IMPROVED_NECROMANCY)) { double necromancySkill = valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::NECROMANCY)/100.0; vstd::amin(necromancySkill, 1.0); //it's impossible to raise more creatures than all... const std::map<ui32,si32> &casualties = battleResult.casualties[!battleResult.winner]; ui32 raisedUnits = 0; // Figure out what to raise and how many. const CreatureID creatureTypes[] = {CreatureID::SKELETON, CreatureID::WALKING_DEAD, CreatureID::WIGHTS, CreatureID::LICHES}; const bool improvedNecromancy = hasBonusOfType(Bonus::IMPROVED_NECROMANCY); const CCreature *raisedUnitType = VLC->creh->creatures[creatureTypes[improvedNecromancy ? necromancyLevel : 0]]; const ui32 raisedUnitHP = raisedUnitType->valOfBonuses(Bonus::STACK_HEALTH); //calculate creatures raised from each defeated stack for (auto & casualtie : casualties) { // Get lost enemy hit points convertible to units. CCreature * c = VLC->creh->creatures[casualtie.first]; const ui32 raisedHP = c->valOfBonuses(Bonus::STACK_HEALTH) * casualtie.second * necromancySkill; raisedUnits += std::min<ui32>(raisedHP / raisedUnitHP, casualtie.second * necromancySkill); //limit to % of HP and % of original stack count } // Make room for new units. SlotID slot = getSlotFor(raisedUnitType->idNumber); if (slot == SlotID()) { // 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 = getSlotFor(raisedUnitType->idNumber); } if (raisedUnits <= 0) raisedUnits = 1; return CStackBasicDescriptor(raisedUnitType->idNumber, raisedUnits); } return CStackBasicDescriptor(); }
SlotID CCreatureSet::getSlotFor(CreatureID creature, ui32 slotsAmount/*=7*/) const /*returns -1 if no slot available */ { return getSlotFor(VLC->creh->creatures[creature], slotsAmount); }