diff --git a/lib/BattleState.cpp b/lib/BattleState.cpp index 178f9b961..5c6fdefb4 100644 --- a/lib/BattleState.cpp +++ b/lib/BattleState.cpp @@ -469,7 +469,7 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp auto handleWarMachine= [&](int side, ArtifactPosition artslot, CreatureID cretype, BattleHex hex) { if(heroes[side] && heroes[side]->getArt(artslot)) - stacks.push_back(curB->generateNewStack(CStackBasicDescriptor(cretype, 1), !side, SlotID(255), hex)); + stacks.push_back(curB->generateNewStack(CStackBasicDescriptor(cretype, 1), !side, SlotID::WAR_MACHINES_SLOT, hex)); }; handleWarMachine(0, ArtifactPosition::MACH1, CreatureID::BALLISTA, 52); @@ -526,15 +526,15 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp if (curB->town && curB->town->fortLevel() >= CGTownInstance::CITADEL) { // keep tower - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -2); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID::ARROW_TOWERS_SLOT, -2); stacks.push_back(stack); if (curB->town->fortLevel() >= CGTownInstance::CASTLE) { // lower tower + upper tower - CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -4); + CStack * stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID::ARROW_TOWERS_SLOT, -4); stacks.push_back(stack); - stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID(255), -3); + stack = curB->generateNewStack(CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), false, SlotID::ARROW_TOWERS_SLOT, -3); stacks.push_back(stack); } @@ -712,7 +712,7 @@ std::shared_ptr BattleInfo::getObstacleOnTile(BattleHex tile) BattlefieldBI::BattlefieldBI BattleInfo::battlefieldTypeToBI(BFieldType bfieldType) { - static const std::map theMap = + static const std::map theMap = { {BFieldType::CLOVER_FIELD, BattlefieldBI::CLOVER_FIELD}, {BFieldType::CURSED_GROUND, BattlefieldBI::CURSED_GROUND}, @@ -1141,7 +1141,7 @@ bool CStack::ableToRetaliate() const //FIXME: crash after clone is killed ui8 CStack::counterAttacksTotal() const { - //after dispell bonus should remain during current round + //after dispell bonus should remain during current round ui8 val = 1 + valOfBonuses(Bonus::ADDITIONAL_RETALIATION); vstd::amax(counterAttacksTotalCache, val); return counterAttacksTotalCache; @@ -1183,9 +1183,9 @@ ui32 CStack::calculateHealedHealthPoints(ui32 toHeal, const bool resurrect) cons ui8 CStack::getSpellSchoolLevel(const CSpell * spell, int * outSelectedSchool) const { int skill = valOfBonuses(Selector::typeSubtype(Bonus::SPELLCASTER, spell->id)); - + vstd::abetween(skill, 0, 3); - + return skill; } diff --git a/lib/GameConstants.cpp b/lib/GameConstants.cpp index 712cdd722..a5a4ca7f1 100644 --- a/lib/GameConstants.cpp +++ b/lib/GameConstants.cpp @@ -19,7 +19,10 @@ #include "spells/CSpellHandler.h" const SlotID SlotID::COMMANDER_SLOT_PLACEHOLDER = SlotID(-2); -const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(255); +const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3); +const SlotID SlotID::WAR_MACHINES_SLOT = SlotID(-4); +const SlotID SlotID::ARROW_TOWERS_SLOT = SlotID(-5); + const PlayerColor PlayerColor::CANNOT_DETERMINE = PlayerColor(253); const PlayerColor PlayerColor::UNFLAGGABLE = PlayerColor(254); const PlayerColor PlayerColor::NEUTRAL = PlayerColor(255); diff --git a/lib/GameConstants.h b/lib/GameConstants.h index 1ece2170a..d75ffade5 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -237,6 +237,8 @@ class SlotID : public BaseForID DLL_LINKAGE static const SlotID COMMANDER_SLOT_PLACEHOLDER; DLL_LINKAGE static const SlotID SUMMONED_SLOT_PLACEHOLDER; ///attackerOwned; - bsa.creID = summonedType; + bsa.creID = summonedType; ui64 risedHp = summoner->count * summoner->valOfBonuses(Bonus::DAEMON_SUMMONING, bsa.creID.toEnum()); ui64 targetHealth = destStack->getCreature()->MaxHealth() * destStack->baseAmount;//todo: ignore AGE effect @@ -5887,7 +5887,7 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, Battl PlayerColor color = army->tempOwner; if(color == PlayerColor::UNFLAGGABLE) color = PlayerColor::NEUTRAL; - + auto killStack = [&, this](const SlotID slot, const CStackInstance * instance) { StackLocation sl(army, slot); @@ -5928,47 +5928,67 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance * _army, Battl for(CStack *st : bat->stacks) { - if(vstd::contains(st->state, EBattleStackState::SUMMONED)) //don't take into account summoned stacks + if(vstd::contains(st->state, EBattleStackState::SUMMONED)) //don't take into account temporary summoned stacks continue; if (st->owner != color) //remove only our stacks continue; + logGlobal->debugStream() << "Calculating casualties for " << st->nodeName(); + //FIXME: this info is also used in BattleInfo::calculateCasualties, refactor st->count = std::max (0, st->count - st->resurrected); - if (!st->count && !st->base) //we can imagine stacks of war machines that are not spawned by artifacts? + if(st->slot == SlotID::ARROW_TOWERS_SLOT) + { + //do nothing + logGlobal->debugStream() << "Ignored arrow towers stack"; + } + else if(st->slot == SlotID::WAR_MACHINES_SLOT) { auto warMachine = VLC->arth->creatureToMachineID(st->type->idNumber); - //catapult artifact remain even if "creature" killed in siege - if(warMachine != ArtifactID::NONE && warMachine != ArtifactID::CATAPULT) + + if(warMachine == ArtifactID::NONE) { + logGlobal->errorStream() << "Invalid creature in war machine virtual slot: " << st->nodeName(); + } + //catapult artifact remain even if "creature" killed in siege + else if(warMachine != ArtifactID::CATAPULT && !st->count) + { + logGlobal->debugStream() << "War machine has been destroyed"; auto hero = dynamic_ptr_cast (army); if (hero) removedWarMachines.push_back (ArtifactLocation(hero, hero->getArtPos(warMachine, true))); + else + logGlobal->errorStream() << "War machine in army without hero"; } } - - if(army->slotEmpty(st->slot)) + else if(st->slot == SlotID::SUMMONED_SLOT_PLACEHOLDER) { - if(st->slot == SlotID::SUMMONED_SLOT_PLACEHOLDER && !vstd::contains(st->state, EBattleStackState::SUMMONED) && st->alive() && st->count > 0) + if(st->alive() && st->count > 0) { + logGlobal->debugStream() << "Stack has been permanently summoned"; //this stack was permanently summoned const CreatureID summonedType = st->type->idNumber; summoned[summonedType] += st->count; - } + } } - else + else if(st->base && !army->slotEmpty(st->slot)) { if(st->count == 0 || !st->alive()) { killStack(st->slot, st->base); + logGlobal->debugStream() << "Stack has been destroyed"; } else if(st->count < army->getStackCount(st->slot)) - { + { StackLocation sl(army, st->slot); newStackCounts.push_back(TStackAndItsNewCount(sl, st->count)); } } + else + { + logGlobal->warnStream() << "Unhandled stack " << st->nodeName(); + } } }