From 8d7629bdabafe16b4aaf79138459ed5891027b7f Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Tue, 2 Feb 2016 11:12:28 +0300 Subject: [PATCH 1/3] Fix unused function warning in release mode --- lib/mapping/CDrawRoadsOperation.cpp | 127 ++++++++++++++-------------- 1 file changed, 64 insertions(+), 63 deletions(-) diff --git a/lib/mapping/CDrawRoadsOperation.cpp b/lib/mapping/CDrawRoadsOperation.cpp index c8fc0cbe1..2bd52a563 100644 --- a/lib/mapping/CDrawRoadsOperation.cpp +++ b/lib/mapping/CDrawRoadsOperation.cpp @@ -12,7 +12,7 @@ #include "CDrawRoadsOperation.h" #include "CMap.h" -const std::vector CDrawRoadsOperation::patterns = +const std::vector CDrawRoadsOperation::patterns = { //single tile. fall-back pattern { @@ -31,7 +31,7 @@ const std::vector CDrawRoadsOperation::pattern { "?","-","+", "-","+","+", - "+","+","?" + "+","+","?" }, {2,5}, {-1,-1}, @@ -43,7 +43,7 @@ const std::vector CDrawRoadsOperation::pattern { "?","-","?", "-","+","+", - "?","+","?" + "?","+","?" }, {0,1}, {0,3}, @@ -55,7 +55,7 @@ const std::vector CDrawRoadsOperation::pattern { "?","-","?", "-","+","+", - "?","-","?" + "?","-","?" }, {15,15},{11,12}, true, @@ -66,7 +66,7 @@ const std::vector CDrawRoadsOperation::pattern { "?","-","?", "-","+","-", - "?","+","?" + "?","+","?" }, {14,14},{9,10}, false, @@ -77,7 +77,7 @@ const std::vector CDrawRoadsOperation::pattern { "?","+","?", "-","+","+", - "?","+","?" + "?","+","?" }, {6,7},{7,8}, true, @@ -88,46 +88,46 @@ const std::vector CDrawRoadsOperation::pattern { "?","-","?", "+","+","+", - "?","+","?" + "?","+","?" }, {8,9},{5,6}, false, true }, - //Straight Horizontal + //Straight Horizontal { { "?","-","?", "+","+","+", - "?","-","?" + "?","-","?" }, {12,13},{11,12}, false, false }, - //Straight Vertical + //Straight Vertical { { "?","+","?", "-","+","-", - "?","+","?" + "?","+","?" }, {10,11},{9,10}, false, false }, - //X-cross + //X-cross { { "?","+","?", "+","+","+", - "?","+","?" + "?","+","?" }, {16,16},{4,4}, false, false - } - + } + }; static bool ruleIsNone(const std::string & rule) @@ -140,45 +140,47 @@ static bool ruleIsSomething(const std::string & rule) return rule == "+"; } +#ifndef NDEBUG static bool ruleIsAny(const std::string & rule) { return rule == "?"; } +#endif ///CDrawRoadsOperation CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, ERoadType::ERoadType roadType, CRandomGenerator * gen): CMapOperation(map),terrainSel(terrainSel), roadType(roadType), gen(gen) { - + } void CDrawRoadsOperation::execute() { std::set invalidated; - + for(const auto & pos : terrainSel.getSelectedItems()) { auto & tile = map->getTile(pos); tile.roadType = roadType; - + auto rect = extendTileAroundSafely(pos); rect.forEach([&invalidated](const int3 & pos) { invalidated.insert(pos); }); } - - updateTiles(invalidated); + + updateTiles(invalidated); } void CDrawRoadsOperation::undo() { - //TODO + //TODO } void CDrawRoadsOperation::redo() { - //TODO + //TODO } std::string CDrawRoadsOperation::getLabel() const @@ -188,14 +190,14 @@ std::string CDrawRoadsOperation::getLabel() const bool CDrawRoadsOperation::canApplyPattern(const RoadPattern & pattern) const { - //TODO: this method should be virtual for river support + //TODO: this method should be virtual for river support return pattern.roadMapping.first >= 0; } void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const { //todo: use cashing here and also in terrain patterns - + if(flip == 0) { return; @@ -217,7 +219,7 @@ void CDrawRoadsOperation::flipPattern(RoadPattern& pattern, int flip) const { std::swap(pattern.data[i], pattern.data[6 + i]); } - } + } } @@ -226,98 +228,98 @@ bool CDrawRoadsOperation::needUpdateTile(const TerrainTile & tile) const return tile.roadType != ERoadType::NO_ROAD; //TODO: this method should be virtual for river support } -void CDrawRoadsOperation::updateTiles(std::set & invalidated) +void CDrawRoadsOperation::updateTiles(std::set & invalidated) { for(int3 coord : invalidated) { TerrainTile & tile = map->getTile(coord); ValidationResult result(false); - + if(!needUpdateTile(tile)) continue; - + int bestPattern = -1; - + for(int k = 0; k < patterns.size(); ++k) { result = validateTile(patterns[k], coord); - + if(result.result) { bestPattern = k; break; } } - + if(bestPattern != -1) { updateTile(tile, patterns[bestPattern], result.flip); } - + } }; bool CDrawRoadsOperation::tileHasSomething(const int3& pos) const { -//TODO: this method should be virtual for river support +//TODO: this method should be virtual for river support - return map->getTile(pos).roadType != ERoadType::NO_ROAD; + return map->getTile(pos).roadType != ERoadType::NO_ROAD; } void CDrawRoadsOperation::updateTile(TerrainTile & tile, const RoadPattern & pattern, const int flip) { - //TODO: this method should be virtual for river support - + //TODO: this method should be virtual for river support + const std::pair & mapping = pattern.roadMapping; - + tile.roadDir = gen->nextInt(mapping.first, mapping.second); - tile.extTileFlags = (tile.extTileFlags & 0xCF) | (flip << 4); + tile.extTileFlags = (tile.extTileFlags & 0xCF) | (flip << 4); } CDrawRoadsOperation::ValidationResult CDrawRoadsOperation::validateTile(const RoadPattern & pattern, const int3 & pos) { ValidationResult result(false); - + if(!canApplyPattern(pattern)) return result; - - + + for(int flip = 0; flip < 4; ++flip) { - if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip)) + if((flip == FLIP_PATTERN_BOTH) && !(pattern.hasHFlip && pattern.hasVFlip)) continue; - if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip) + if((flip == FLIP_PATTERN_HORIZONTAL) && !pattern.hasHFlip) continue; - if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip)) + if((flip == FLIP_PATTERN_VERTICAL) && !(pattern.hasVFlip)) continue; - - RoadPattern flipped = pattern; - + + RoadPattern flipped = pattern; + flipPattern(flipped, flip); - + bool validated = true; - + for(int i = 0; i < 9; ++i) { if(4 == i) continue; int cx = pos.x + (i % 3) - 1; int cy = pos.y + (i / 3) - 1; - + int3 currentPos(cx, cy, pos.z); - + bool hasSomething; - + if(!map->isInTheMap(currentPos)) { hasSomething = true; //road/river can go out of map } else { - hasSomething = tileHasSomething(currentPos); + hasSomething = tileHasSomething(currentPos); } - + if(ruleIsSomething(flipped.data[i])) { if(!hasSomething) @@ -332,23 +334,22 @@ CDrawRoadsOperation::ValidationResult CDrawRoadsOperation::validateTile(const Ro { validated = false; break; - } + } } else { - assert(ruleIsAny(flipped.data[i])); - } - + assert(ruleIsAny(flipped.data[i])); + } + } - + if(validated) { result.result = true; result.flip = flip; - return result; - } + return result; + } } - + return result; } - From bdd87be10d58b52a40acd81df0bd6f61b80fa749 Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Tue, 2 Feb 2016 11:11:54 +0300 Subject: [PATCH 2/3] Try to fix http://bugs.vcmi.eu/view.php?id=2362 --- client/windows/CSpellWindow.cpp | 62 +++++++++++++------------- lib/spells/CDefaultSpellMechanics.cpp | 64 +++++++++++++++------------ 2 files changed, 66 insertions(+), 60 deletions(-) diff --git a/client/windows/CSpellWindow.cpp b/client/windows/CSpellWindow.cpp index 67e9a81f3..4ae3bbc5d 100644 --- a/client/windows/CSpellWindow.cpp +++ b/client/windows/CSpellWindow.cpp @@ -6,6 +6,7 @@ #include "CAdvmapInterface.h" #include "GUIClasses.h" #include "InfoWindows.h" +#include "CCastleInterface.h" #include "../CBitmapHandler.h" #include "../CDefHandler.h" @@ -109,7 +110,7 @@ CSpellWindow::CSpellWindow(const SDL_Rect &, const CGHeroInstance * _myHero, CPl Uint8 *sitesPerOurTab = s.combatSpell ? sitesPerTabBattle : sitesPerTabAdv; ++sitesPerOurTab[4]; - + s.forEachSchool([&sitesPerOurTab](const SpellSchoolInfo & school, bool & stop) { ++sitesPerOurTab[(ui8)school.id]; @@ -156,9 +157,9 @@ CSpellWindow::CSpellWindow(const SDL_Rect &, const CGHeroInstance * _myHero, CPl leftCorner = BitmapHandler::loadBitmap("SpelTrnL.bmp", true); rightCorner = BitmapHandler::loadBitmap("SpelTrnR.bmp", true); - + spells = new CAnimation("Spells.def"); - + spellTab = CDefHandler::giveDef("SpelTab.def"); schools = CDefHandler::giveDef("Schools.def"); schoolBorders[0] = CDefHandler::giveDef("SplevA.def"); @@ -380,9 +381,9 @@ public: if(A.levelB.level) - return false; - - + return false; + + for(ui8 schoolId = 0; schoolId < 4; schoolId++) { if(A.school.at((ESpellSchool)schoolId) && !B.school.at((ESpellSchool)schoolId)) @@ -390,7 +391,7 @@ public: if(!A.school.at((ESpellSchool)schoolId) && B.school.at((ESpellSchool)schoolId)) return false; } - + return A.name < B.name; } } spellsorter; @@ -400,8 +401,8 @@ void CSpellWindow::computeSpellsPerArea() std::vector spellsCurSite; for(const SpellID & spellID : mySpells) { - CSpell * s = spellID.toSpell(); - + CSpell * s = spellID.toSpell(); + if(s->combatSpell ^ !battleSpellsOnly && ((selectedTab == 4) || (s->school[(ESpellSchool)selectedTab])) ) @@ -533,7 +534,7 @@ void CSpellWindow::keyPressed(const SDL_KeyboardEvent & key) { fexitb(); return; - } + } if(key.state == SDL_PRESSED) { @@ -622,10 +623,9 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) owner->myInt->showInfoDialog(std::string(msgBuf)); return; } - //battle spell on adv map or adventure map spell during combat => display infowindow, not cast if((sp->isCombatSpell() && !owner->myInt->battleInt) - || (sp->isAdventureSpell() && owner->myInt->battleInt)) + || (sp->isAdventureSpell() && (owner->myInt->battleInt || owner->myInt->castleInt))) { std::vector hlp(1, new CComponent(CComponent::spell, mySpell, 0)); LOCPLINT->showInfoDialog(sp->getLevelInfo(schoolLevel).description, hlp); @@ -705,26 +705,26 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) { const CGHeroInstance *h = owner->myHero; GH.popInt(owner); - - auto guard = vstd::makeScopeGuard([this] + + auto guard = vstd::makeScopeGuard([this] { (LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastTabBattle : owner->myInt->spellbookSettings.spellbookLastTabAdvmap) = owner->selectedTab; - (LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastPageBattle : owner->myInt->spellbookSettings.spellbokLastPageAdvmap) = owner->currentPage; + (LOCPLINT->battleInt ? owner->myInt->spellbookSettings.spellbookLastPageBattle : owner->myInt->spellbookSettings.spellbokLastPageAdvmap) = owner->currentPage; delete owner; - }); + }); if(mySpell == SpellID::TOWN_PORTAL) { //special case //todo: move to mechanics - + std::vector availableTowns; std::vector Towns = LOCPLINT->cb->getTownsInfo(false); vstd::erase_if(Towns, [this](const CGTownInstance * t) { - const auto relations = owner->myInt->cb->getPlayerRelations(t->tempOwner, owner->myInt->playerID); - return relations == PlayerRelations::ENEMIES; + const auto relations = owner->myInt->cb->getPlayerRelations(t->tempOwner, owner->myInt->playerID); + return relations == PlayerRelations::ENEMIES; }); if (Towns.empty()) @@ -776,13 +776,13 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) availableTowns.push_back(t->id.getNum());//add to the list } } - + auto castTownPortal = [h](int townId) { const CGTownInstance * dest = LOCPLINT->cb->getTown(ObjectInstanceID(townId)); - LOCPLINT->cb->castSpell(h, SpellID::TOWN_PORTAL, dest->visitablePos()); + LOCPLINT->cb->castSpell(h, SpellID::TOWN_PORTAL, dest->visitablePos()); }; - + if (availableTowns.empty()) LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[124]); else @@ -791,13 +791,13 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) CGI->generaltexth->jktexts[40], CGI->generaltexth->jktexts[41], castTownPortal)); } - return; + return; } - + if(mySpell == SpellID::SUMMON_BOAT) { //special case - //todo: move to mechanics + //todo: move to mechanics int3 pos = h->bestLocation(); if(pos.x < 0) { @@ -805,10 +805,10 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) return; } } - + if(sp->getTargetType() == CSpell::LOCATION) { - adventureInt->enterCastingMode(sp); + adventureInt->enterCastingMode(sp); } else if(sp->getTargetType() == CSpell::NO_TARGET) { @@ -817,7 +817,7 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState) else { logGlobal->error("Invalid spell target type"); - } + } } } } @@ -865,11 +865,11 @@ void CSpellWindow::SpellArea::showAll(SDL_Surface * to) if(mySpell < 0) return; - const CSpell * spell = mySpell.toSpell(); + const CSpell * spell = mySpell.toSpell(); owner->spells->load(mySpell); - + IImage * icon = owner->spells->getImage(mySpell,0,false); - + if(icon != nullptr) icon->draw(to, pos.x, pos.y); else diff --git a/lib/spells/CDefaultSpellMechanics.cpp b/lib/spells/CDefaultSpellMechanics.cpp index a8f77e476..c9a788f88 100644 --- a/lib/spells/CDefaultSpellMechanics.cpp +++ b/lib/spells/CDefaultSpellMechanics.cpp @@ -154,6 +154,13 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve } const CGHeroInstance * caster = parameters.caster; + + if(caster->inTownGarrison) + { + env->complain("Attempt to cast an adventure spell in town garrison"); + return false; + } + const int cost = caster->getSpellCost(owner); if(!caster->canCastThisSpell(owner)) @@ -174,7 +181,7 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve asc.spellID = owner->id; env->sendAndApply(&asc); } - + switch(applyAdventureEffects(env, parameters)) { case ESpellCastResult::OK: @@ -184,7 +191,7 @@ bool DefaultSpellMechanics::adventureCast(const SpellCastEnvironment * env, Adve sm.absolute = false; sm.val = -cost; env->sendAndApply(&sm); - return true; + return true; } break; case ESpellCastResult::CANCEL: @@ -224,16 +231,16 @@ ESpellCastResult DefaultSpellMechanics::applyAdventureEffects(const SpellCastEnv void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const { logGlobal->debugStream() << "Started spell cast. Spell: "<name<<"; mode:"<complain("No spell-caster provided."); - return; + return; } - + BattleSpellCast sc; prepareBattleCast(parameters, sc); - + //check it there is opponent hero const ui8 otherSide = 1-parameters.casterSide; const CGHeroInstance * otherHero = nullptr; @@ -247,7 +254,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS spellCost = parameters.cb->battleGetSpellCost(owner, parameters.casterHero); if(nullptr != otherHero) //handle mana channel - { + { int manaChannel = 0; for(const CStack * stack : parameters.cb->battleGetAllStacks(true)) //TODO: shouldn't bonus system handle it somehow? { @@ -271,10 +278,10 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; std::vector reflected;//for magic mirror - //checking if creatures resist + //checking if creatures resist handleResistance(env, attackedCres, sc); //it is actual spell and can be reflected to single target, no recurrence - const bool tryMagicMirror = owner->isNegative() && owner->level && owner->getLevelInfo(0).range == "0"; + const bool tryMagicMirror = owner->isNegative() && owner->level && owner->getLevelInfo(0).range == "0"; if(tryMagicMirror) { for(auto s : attackedCres) @@ -295,7 +302,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS effect.effect = 3; effect.stack = s->ID; sc.customEffects.push_back(effect); - } + } } for(auto cre : attackedCres) @@ -376,13 +383,13 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS } } -void DefaultSpellMechanics::battleLogSingleTarget(std::vector & logLines, const BattleSpellCast * packet, +void DefaultSpellMechanics::battleLogSingleTarget(std::vector & logLines, const BattleSpellCast * packet, const std::string & casterName, const CStack * attackedStack, bool & displayDamage) const { const std::string attackedName = attackedStack->getName(); const std::string attackedNameSing = attackedStack->getCreature()->nameSing; const std::string attackedNamePl = attackedStack->getCreature()->namePl; - + auto getPluralFormat = [attackedStack](const int baseTextID) -> boost::format { return boost::format(VLC->generaltexth->allTexts[(attackedStack->count > 1 ? baseTextID + 1 : baseTextID)]); @@ -470,7 +477,7 @@ void DefaultSpellMechanics::battleLogSingleTarget(std::vector & log logLines.push_back(text.str()); } break; - } + } } void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const @@ -479,7 +486,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, if(owner->isOffensiveSpell()) { int spellDamage = parameters.effectValue; - + int chainLightningModifier = 0; for(auto & attackedCre : ctx.attackedCres) { @@ -522,13 +529,13 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, vstd::amax(maxDuration, b.turnsRemain); sse.effect.push_back(b); } - //if all spell effects have special duration, use it - duration = maxDuration; + //if all spell effects have special duration, use it + duration = maxDuration; } //fix to original config: shield should display damage reduction if(owner->id == SpellID::SHIELD || owner->id == SpellID::AIR_SHIELD) { - sse.effect.back().val = (100 - sse.effect.back().val); + sse.effect.back().val = (100 - sse.effect.back().val); } //we need to know who cast Bind if(owner->id == SpellID::BIND && parameters.casterStack) @@ -593,7 +600,7 @@ void DefaultSpellMechanics::applyBattleEffects(const SpellCastEnvironment * env, if(!sse.stacks.empty()) env->sendAndApply(&sse); - } + } } std::vector DefaultSpellMechanics::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const @@ -738,7 +745,7 @@ std::set DefaultSpellMechanics::getAffectedStacks(SpellTargeting ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCast(const CBattleInfoCallback * cb, PlayerColor player) const { - //no problems by default, this method is for spell-specific problems + //no problems by default, this method is for spell-specific problems return ESpellCastProblem::OK; } @@ -756,7 +763,7 @@ void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast if(sourceSpell != nullptr) { //Special case: DISRUPTING_RAY is "immune" to dispell - //Other even PERMANENT effects can be removed (f.e. BIND) + //Other even PERMANENT effects can be removed (f.e. BIND) if(sourceSpell->id == SpellID::DISRUPTING_RAY) return false; } @@ -766,7 +773,7 @@ void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast { CStack *s = battle->getStack(stackID); s->popBonuses(CSelector(localSelector).And(selector)); - } + } } void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters) const @@ -781,12 +788,12 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat if(!destination.isValid()) { env->complain("MagicMirror: invalid destination"); - return; + return; } BattleSpellCast sc; prepareBattleCast(parameters, sc); - + //calculating affected creatures for all spells //must be vector, as in Chain Lightning order matters std::vector attackedCres; //CStack vector is somewhat more suitable than ID vector @@ -802,14 +809,14 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat { sc.affectedCres.insert(cre->ID); } - + StacksInjured si; SpellCastContext ctx(attackedCres, sc, si); applyBattleEffects(env, parameters, ctx); env->sendAndApply(&sc); if(!si.stacks.empty()) //after spellcast info shows - env->sendAndApply(&si); + env->sendAndApply(&si); logGlobal->debugStream() << "Finished spell cast. Spell: "<name<<"; mode: MAGIC_MIRROR"; } @@ -842,8 +849,8 @@ void DefaultSpellMechanics::handleResistance(const SpellCastEnvironment * env, s effect.effect = 78; effect.stack = s->ID; sc.customEffects.push_back(effect); - } - } + } + } } void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& parameters, BattleSpellCast& sc) const @@ -855,6 +862,5 @@ void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& p sc.dmgToDisplay = 0; sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING; sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1); - sc.manaGained = 0; + sc.manaGained = 0; } - From eb10433535bdbf8d6bcf4ac63c3751cd56f4539b Mon Sep 17 00:00:00 2001 From: Vadim Markovtsev Date: Mon, 1 Feb 2016 20:03:57 +0300 Subject: [PATCH 3/3] Implement psychic elementals vs mind immune units --- lib/CBattleCallback.cpp | 63 ++++++++++++++++++++++------------------- lib/GameConstants.h | 5 +--- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/lib/CBattleCallback.cpp b/lib/CBattleCallback.cpp index bdfb2580e..83200213b 100644 --- a/lib/CBattleCallback.cpp +++ b/lib/CBattleCallback.cpp @@ -187,11 +187,11 @@ TStacks CBattleInfoEssentials::battleGetStacksIf(TStackFilter predicate, bool in { TStacks ret; RETURN_IF_NOT_BATTLE(ret); - + vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){ return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS)); }); - + return ret; } @@ -784,23 +784,23 @@ std::vector CBattleInfoCallback::battleGetAvailableHexes(const CStack bool CBattleInfoCallback::battleCanAttack(const CStack * stack, const CStack * target, BattleHex dest) const { RETURN_IF_NOT_BATTLE(false); - + if(battleTacticDist()) return false; - + if (!stack || !target) return false; - + if (stack->owner == target->owner) return false; - + auto &id = stack->getCreature()->idNumber; if (id == CreatureID::FIRST_AID_TENT || id == CreatureID::CATAPULT) return false; - + if (!target->alive()) return false; - + return true; } @@ -997,7 +997,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c const bool distPenalty = !info.attackerBonuses->hasBonusOfType(Bonus::NO_DISTANCE_PENALTY) && battleHasDistancePenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition); const bool obstaclePenalty = battleHasWallPenalty(info.attackerBonuses, info.attackerPosition, info.defenderPosition); - if (info.shooting) + if(info.shooting) { if (distPenalty || info.defenderBonuses->hasBonus(isAdvancedAirShield)) { @@ -1013,9 +1013,14 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c multBonus *= 0.5; } + // psychic elementals versus mind immune units 50% + if(attackerType->idNumber == CreatureID::PSYCHIC_ELEMENTAL + && info.defenderBonuses->hasBonusOfType(Bonus::MIND_IMMUNITY)) + { + multBonus *= 0.5; + } // TODO attack on petrified unit 50% - // psychic elementals versus mind immune units 50% // blinded unit retaliates minDmg *= additiveBonus * multBonus; @@ -1265,8 +1270,8 @@ std::pair CBattleInfoCallback::getNearestStack(const // I hate std::pairs with their undescriptive member names first / second struct DistStack { - int distanceToPred; - BattleHex destination; + int distanceToPred; + BattleHex destination; const CStack *stack; }; @@ -1276,7 +1281,7 @@ std::pair CBattleInfoCallback::getNearestStack(const { return s != closest && s->alive() && (boost::logic::indeterminate(attackerOwned) || s->attackerOwned == attackerOwned); }, false); - + for(const CStack * st : possibleStacks) for(BattleHex hex : avHexes) if(CStack::isMeleeAttackPossible(closest, st, hex)) @@ -1628,9 +1633,9 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL; const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCast(this, player); - + if(specificProblem != ESpellCastProblem::OK) - return specificProblem; + return specificProblem; if(spell->isNegative() || spell->hasEffects()) { @@ -1667,7 +1672,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell { bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack); bool casterStack = stack->owner == caster->getOwner(); - + if(!immune) { switch (spell->positiveness) @@ -1716,12 +1721,12 @@ std::vector CBattleInfoCallback::battleGetPossibleTargets(PlayerColor { const CGHeroInstance * caster = battleGetFightingHero(playerToSide(player)); //TODO const CSpell::TargetInfo ti(spell, caster->getSpellSchoolLevel(spell)); - + for(const CStack * stack : battleAliveStacks()) { bool immune = ESpellCastProblem::OK != spell->isImmuneByStack(caster, stack); bool casterStack = stack->owner == caster->getOwner(); - + if(!immune) switch (spell->positiveness) { @@ -1784,7 +1789,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell { logGlobal->errorStream() << "CBattleInfoCallback::battleCanCastThisSpellHere: no spellcaster."; return ESpellCastProblem::INVALID; - } + } const PlayerColor player = caster->getOwner(); ESpellCastProblem::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(caster, spell, mode); if(moreGeneralProblem != ESpellCastProblem::OK) @@ -1894,19 +1899,19 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co RETURN_IF_NOT_BATTLE(SpellID::NONE); //This is complete list. No spells from mods. //todo: this should be Spellbook of caster Stack - static const std::set allPossibleSpells = + static const std::set allPossibleSpells = { SpellID::AIR_SHIELD, SpellID::ANTI_MAGIC, - SpellID::BLESS, + SpellID::BLESS, SpellID::BLOODLUST, SpellID::COUNTERSTRIKE, SpellID::CURE, - SpellID::FIRE_SHIELD, + SpellID::FIRE_SHIELD, SpellID::FORTUNE, SpellID::HASTE, SpellID::MAGIC_MIRROR, - SpellID::MIRTH, + SpellID::MIRTH, SpellID::PRAYER, SpellID::PRECISION, SpellID::PROTECTION_FROM_AIR, @@ -1918,7 +1923,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co SpellID::STONE_SKIN }; std::vector beneficialSpells; - + auto getAliveEnemy = [=](const std::function & pred) { return getStackIf([=](const CStack * stack) @@ -1938,7 +1943,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co { case SpellID::SHIELD: case SpellID::FIRE_SHIELD: // not if all enemy units are shooters - { + { auto walker = getAliveEnemy([&](const CStack * stack) //look for enemy, non-shooting stack { return !stack->shots; @@ -1963,7 +1968,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co case SpellID::PROTECTION_FROM_AIR: case SpellID::PROTECTION_FROM_EARTH: case SpellID::PROTECTION_FROM_FIRE: - case SpellID::PROTECTION_FROM_WATER: + case SpellID::PROTECTION_FROM_WATER: { const ui8 enemySide = (ui8)subject->attackerOwned; //todo: only if enemy has spellbook @@ -2006,7 +2011,7 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co } break; } - beneficialSpells.push_back(spellID); + beneficialSpells.push_back(spellID); } if(!beneficialSpells.empty()) @@ -2190,13 +2195,13 @@ TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AN { ASSERT_IF_CALLED_WITH_PLAYER } - + return battleGetStacksIf([=](const CStack * s){ const bool ownerMatches = (whose == MINE_AND_ENEMY) || (whose == ONLY_MINE && s->owner == player) || (whose == ONLY_ENEMY && s->owner != player); const bool alivenessMatches = s->alive() || !onlyAlive; - return ownerMatches && alivenessMatches; + return ownerMatches && alivenessMatches; }); } diff --git a/lib/GameConstants.h b/lib/GameConstants.h index d75ffade5..fe222eb68 100644 --- a/lib/GameConstants.h +++ b/lib/GameConstants.h @@ -968,6 +968,7 @@ public: WATER_ELEMENTAL = 115, GOLD_GOLEM = 116, DIAMOND_GOLEM = 117, + PSYCHIC_ELEMENTAL = 120, CATAPULT = 145, BALLISTA = 146, FIRST_AID_TENT = 147, @@ -1053,7 +1054,3 @@ typedef int TRmgTemplateZoneId; #undef ID_LIKE_OPERATORS_INTERNAL #undef INSTID_LIKE_CLASS_COMMON #undef OP_DECL_INT - - - -