mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
TurnInfo: store all bonuses and use TileInfo for everything
Currently this going to break ONE_WEEK bonuses because those don't work with CWillLastDays selector.
This commit is contained in:
parent
9ed9d94009
commit
abc4ea272f
@ -50,11 +50,11 @@ CPathfinder::CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstan
|
||||
}
|
||||
|
||||
hlp = make_unique<CPathfinderHelper>(hero);
|
||||
if(hlp->ti->bonusFlying)
|
||||
if(hlp->hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
||||
options.useFlying = true;
|
||||
if(hlp->ti->bonusWaterWalking)
|
||||
if(hlp->hasBonusOfType(Bonus::WATER_WALKING))
|
||||
options.useWaterWalking = true;
|
||||
if(CGWhirlpool::isProtected(hero))
|
||||
if(hlp->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
|
||||
options.useTeleportWhirlpool = true;
|
||||
|
||||
initializeGraph();
|
||||
@ -109,7 +109,7 @@ void CPathfinder::calculatePaths()
|
||||
if(!movement)
|
||||
{
|
||||
hlp->updateTurnInfo(++turn);
|
||||
movement = hlp->getMaxMovePoints(cp->layer, turn);
|
||||
movement = hlp->getMaxMovePoints(cp->layer);
|
||||
}
|
||||
|
||||
//add accessible neighbouring nodes to the queue
|
||||
@ -140,11 +140,11 @@ void CPathfinder::calculatePaths()
|
||||
continue;
|
||||
|
||||
destAction = getDestAction();
|
||||
int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, movement, hlp->getTurnInfo(turn));
|
||||
int cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, movement, hlp->getTurnInfo());
|
||||
int remains = movement - cost;
|
||||
if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK)
|
||||
{
|
||||
remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1);
|
||||
remains = hero->movementPointsAfterEmbark(movement, cost, destAction - 1, hlp->getTurnInfo());
|
||||
cost = movement - remains;
|
||||
}
|
||||
int turnAtNextTile = turn;
|
||||
@ -152,8 +152,8 @@ void CPathfinder::calculatePaths()
|
||||
{
|
||||
//occurs rarely, when hero with low movepoints tries to leave the road
|
||||
hlp->updateTurnInfo(++turnAtNextTile);
|
||||
int moveAtNextTile = hlp->getMaxMovePoints(i, turnAtNextTile);
|
||||
cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile, hlp->getTurnInfo(turnAtNextTile)); //cost must be updated, movement points changed :(
|
||||
int moveAtNextTile = hlp->getMaxMovePoints(i);
|
||||
cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile, hlp->getTurnInfo()); //cost must be updated, movement points changed :(
|
||||
remains = moveAtNextTile - cost;
|
||||
}
|
||||
|
||||
@ -285,13 +285,13 @@ bool CPathfinder::isLayerAvailable(const ELayer layer, const int turn) const
|
||||
switch(layer)
|
||||
{
|
||||
case ELayer::AIR:
|
||||
if(!hlp->ti->bonusFlying)
|
||||
if(!hlp->hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
||||
return false;
|
||||
|
||||
break;
|
||||
|
||||
case ELayer::WATER:
|
||||
if(!hlp->ti->bonusWaterWalking)
|
||||
if(!hlp->hasBonusOfType(Bonus::WATER_WALKING))
|
||||
return false;
|
||||
|
||||
break;
|
||||
@ -701,47 +701,63 @@ bool CPathfinder::canVisitObject() const
|
||||
return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL;
|
||||
}
|
||||
|
||||
TurnInfo::TurnInfo(const CGHeroInstance * h, const int Turn)
|
||||
: turn(Turn)
|
||||
TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn)
|
||||
: hero(Hero), maxMovePointsLand(-1), maxMovePointsWater(-1)
|
||||
{
|
||||
maxMovePointsLand = h->maxMovePoints(true);
|
||||
maxMovePointsWater = h->maxMovePoints(false);
|
||||
bonusFlying = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
|
||||
bonusWaterWalking = h->getBonusAtTurn(Bonus::WATER_WALKING, turn);
|
||||
bonuses = hero->getAllBonuses(Selector::days(turn), nullptr);
|
||||
}
|
||||
|
||||
bool TurnInfo::hasBonusOfType(Bonus::BonusType type, int subtype) const
|
||||
{
|
||||
return bonuses->getFirst(Selector::type(type).And(Selector::subtype(subtype)));
|
||||
}
|
||||
|
||||
int TurnInfo::valOfBonuses(Bonus::BonusType type, int subtype) const
|
||||
{
|
||||
return bonuses->valOfBonuses(Selector::type(type).And(Selector::subtype(subtype)));
|
||||
}
|
||||
|
||||
int TurnInfo::getMaxMovePoints(const EPathfindingLayer layer) const
|
||||
{
|
||||
if(maxMovePointsLand == -1)
|
||||
maxMovePointsLand = hero->maxMovePoints(true, this);
|
||||
if(maxMovePointsWater == -1)
|
||||
maxMovePointsWater = hero->maxMovePoints(false, this);
|
||||
|
||||
return layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
|
||||
}
|
||||
|
||||
CPathfinderHelper::CPathfinderHelper(const CGHeroInstance * Hero)
|
||||
: ti(nullptr), hero(Hero)
|
||||
: turn(0), hero(Hero)
|
||||
{
|
||||
turnsInfo.reserve(16);
|
||||
updateTurnInfo();
|
||||
}
|
||||
|
||||
void CPathfinderHelper::updateTurnInfo(const int turn)
|
||||
void CPathfinderHelper::updateTurnInfo(const int Turn)
|
||||
{
|
||||
if(!ti || ti->turn != turn)
|
||||
if(turn != Turn)
|
||||
{
|
||||
if(turn < turnsInfo.size())
|
||||
ti = turnsInfo[turn];
|
||||
else
|
||||
turn = Turn;
|
||||
if(turn >= turnsInfo.size())
|
||||
{
|
||||
ti = new TurnInfo(hero, turn);
|
||||
auto ti = new TurnInfo(hero, turn);
|
||||
turnsInfo.push_back(ti);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const TurnInfo * CPathfinderHelper::getTurnInfo(const int turn) const
|
||||
const TurnInfo * CPathfinderHelper::getTurnInfo() const
|
||||
{
|
||||
return turnsInfo[turn];
|
||||
}
|
||||
|
||||
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer layer, const int turn) const
|
||||
bool CPathfinderHelper::hasBonusOfType(const Bonus::BonusType type, const int subtype) const
|
||||
{
|
||||
return turnsInfo[turn]->hasBonusOfType(type, subtype);
|
||||
}
|
||||
|
||||
int CPathfinderHelper::getMaxMovePoints(const EPathfindingLayer layer) const
|
||||
{
|
||||
return turnsInfo[turn]->getMaxMovePoints(layer);
|
||||
}
|
||||
@ -796,17 +812,17 @@ int CPathfinderHelper::getMovementCost(const CGHeroInstance * h, const int3 & sr
|
||||
auto s = h->cb->getTile(src), d = h->cb->getTile(dst);
|
||||
int ret = h->getTileCost(*d, *s, ti);
|
||||
|
||||
if(d->blocked && ti->bonusFlying)
|
||||
if(d->blocked && ti->hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
||||
{
|
||||
ret *= (100.0 + ti->bonusFlying->val) / 100.0;
|
||||
ret *= (100.0 + ti->valOfBonuses(Bonus::FLYING_MOVEMENT)) / 100.0;
|
||||
}
|
||||
else if(d->terType == ETerrainType::WATER)
|
||||
{
|
||||
if(h->boat && s->hasFavourableWinds() && d->hasFavourableWinds()) //Favourable Winds
|
||||
ret *= 0.666;
|
||||
else if(!h->boat && ti->bonusWaterWalking)
|
||||
else if(!h->boat && ti->hasBonusOfType(Bonus::WATER_WALKING))
|
||||
{
|
||||
ret *= (100.0 + ti->bonusWaterWalking->val) / 100.0;
|
||||
ret *= (100.0 + ti->valOfBonuses(Bonus::WATER_WALKING)) / 100.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,28 +192,30 @@ private:
|
||||
|
||||
};
|
||||
|
||||
struct TurnInfo
|
||||
struct DLL_LINKAGE TurnInfo
|
||||
{
|
||||
int turn;
|
||||
int maxMovePointsLand;
|
||||
int maxMovePointsWater;
|
||||
const Bonus * bonusFlying;
|
||||
const Bonus * bonusWaterWalking;
|
||||
const CGHeroInstance * hero;
|
||||
TBonusListPtr bonuses;
|
||||
mutable int maxMovePointsLand;
|
||||
mutable int maxMovePointsWater;
|
||||
|
||||
TurnInfo(const CGHeroInstance * h, const int Turn = 0);
|
||||
TurnInfo(const CGHeroInstance * Hero, const int Turn = 0);
|
||||
bool hasBonusOfType(const Bonus::BonusType type, const int subtype = -1) const;
|
||||
int valOfBonuses(const Bonus::BonusType type, const int subtype = -1) const;
|
||||
int getMaxMovePoints(const EPathfindingLayer layer) const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CPathfinderHelper
|
||||
{
|
||||
public:
|
||||
TurnInfo * ti;
|
||||
int turn;
|
||||
const CGHeroInstance * hero;
|
||||
|
||||
CPathfinderHelper(const CGHeroInstance * Hero);
|
||||
void updateTurnInfo(const int turn = 0);
|
||||
const TurnInfo * getTurnInfo(const int turn) const;
|
||||
int getMaxMovePoints(const EPathfindingLayer layer, const int turn) const;
|
||||
const TurnInfo * getTurnInfo() const;
|
||||
bool hasBonusOfType(const Bonus::BonusType type, const int subtype = -1) const;
|
||||
int getMaxMovePoints(const EPathfindingLayer layer) const;
|
||||
|
||||
static void getNeighbours(CGameState * gs, const TerrainTile & srct, const int3 & tile, std::vector<int3> & vec, const boost::logic::tribool & onLand, const bool limitCoastSailing);
|
||||
|
||||
|
@ -80,7 +80,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &fro
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(!getBonusAtTurn(Bonus::NO_TERRAIN_PENALTY, ti->turn, from.terType))
|
||||
else if(!ti->hasBonusOfType(Bonus::NO_TERRAIN_PENALTY, from.terType))
|
||||
{
|
||||
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army.
|
||||
// This is clearly bug in H3 however intended behaviour is not clear.
|
||||
@ -129,11 +129,6 @@ int3 CGHeroInstance::getPosition(bool h3m) const //h3m=true - returns position o
|
||||
}
|
||||
}
|
||||
|
||||
const Bonus * CGHeroInstance::getBonusAtTurn(const Bonus::BonusType &type, const int &turn, const TBonusSubtype &subType) const
|
||||
{
|
||||
return getBonus(Selector::type(type).And(Selector::days(turn)).And(Selector::subtype(subType)));
|
||||
}
|
||||
|
||||
ui8 CGHeroInstance::getSecSkillLevel(SecondarySkill skill) const
|
||||
{
|
||||
for(auto & elem : secSkills)
|
||||
@ -176,8 +171,11 @@ bool CGHeroInstance::canLearnSkill() const
|
||||
return secSkills.size() < GameConstants::SKILL_PER_HERO;
|
||||
}
|
||||
|
||||
int CGHeroInstance::maxMovePoints(bool onLand) const
|
||||
int CGHeroInstance::maxMovePoints(bool onLand, const TurnInfo * ti) const
|
||||
{
|
||||
if(!ti)
|
||||
ti = new TurnInfo(this);
|
||||
|
||||
int base;
|
||||
|
||||
if(onLand)
|
||||
@ -196,10 +194,10 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
|
||||
}
|
||||
|
||||
const Bonus::BonusType bt = onLand ? Bonus::LAND_MOVEMENT : Bonus::SEA_MOVEMENT;
|
||||
const int bonus = valOfBonuses(Bonus::MOVEMENT) + valOfBonuses(bt);
|
||||
const int bonus = ti->valOfBonuses(Bonus::MOVEMENT) + ti->valOfBonuses(bt);
|
||||
|
||||
const int subtype = onLand ? SecondarySkill::LOGISTICS : SecondarySkill::NAVIGATION;
|
||||
const double modifier = valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, subtype) / 100.0;
|
||||
const double modifier = ti->valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, subtype) / 100.0;
|
||||
|
||||
return int(base* (1+modifier)) + bonus;
|
||||
}
|
||||
@ -1166,9 +1164,12 @@ CBonusSystemNode * CGHeroInstance::whereShouldBeAttached(CGameState *gs)
|
||||
return CArmedInstance::whereShouldBeAttached(gs);
|
||||
}
|
||||
|
||||
int CGHeroInstance::movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark /*= false*/) const
|
||||
int CGHeroInstance::movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark /*= false*/, const TurnInfo * ti) const
|
||||
{
|
||||
if(hasBonusOfType(Bonus::FREE_SHIP_BOARDING))
|
||||
if(!ti)
|
||||
ti = new TurnInfo(this);
|
||||
|
||||
if(ti->hasBonusOfType(Bonus::FREE_SHIP_BOARDING))
|
||||
return (MPsBefore - basicCost) * static_cast<double>(maxMovePoints(disembark)) / maxMovePoints(!disembark);
|
||||
|
||||
return 0; //take all MPs otherwise
|
||||
|
@ -134,7 +134,6 @@ public:
|
||||
ui32 getLowestCreatureSpeed() const;
|
||||
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
|
||||
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
|
||||
const Bonus * getBonusAtTurn(const Bonus::BonusType &type, const int &turn = 0, const TBonusSubtype &subType = -1) const;
|
||||
int getCurrentLuck(int stack=-1, bool town=false) const;
|
||||
int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored
|
||||
|
||||
@ -161,8 +160,8 @@ public:
|
||||
void setSecSkillLevel(SecondarySkill which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
|
||||
void levelUp(std::vector<SecondarySkill> skills);
|
||||
|
||||
int maxMovePoints(bool onLand) const;
|
||||
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
|
||||
int maxMovePoints(bool onLand, const TurnInfo * ti = nullptr) const;
|
||||
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false, const TurnInfo * ti = nullptr) const;
|
||||
|
||||
static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
|
||||
double getFightingStrength() const; // takes attack / defense skill into account
|
||||
|
@ -1778,9 +1778,10 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
|
||||
tmh.movePoints = h->movement;
|
||||
|
||||
//check if destination tile is available
|
||||
const bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT);
|
||||
const bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING);
|
||||
const int cost = CPathfinderHelper::getMovementCost(h, h->getPosition(), hmpos, h->movement);
|
||||
auto ti = new TurnInfo(h);
|
||||
const bool canFly = ti->hasBonusOfType(Bonus::FLYING_MOVEMENT);
|
||||
const bool canWalkOnSea = ti->hasBonusOfType(Bonus::WATER_WALKING);
|
||||
const int cost = CPathfinderHelper::getMovementCost(h, h->getPosition(), hmpos, h->movement, ti);
|
||||
|
||||
//it's a rock or blocked and not visitable tile
|
||||
//OR hero is on land and dest is water and (there is not present only one object - boat)
|
||||
@ -1872,14 +1873,14 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
|
||||
|
||||
if(!transit && embarking)
|
||||
{
|
||||
tmh.movePoints = h->movementPointsAfterEmbark(h->movement, cost, false);
|
||||
tmh.movePoints = h->movementPointsAfterEmbark(h->movement, cost, false, ti);
|
||||
return doMove(TryMoveHero::EMBARK, IGNORE_GUARDS, DONT_VISIT_DEST, LEAVING_TILE);
|
||||
//attack guards on embarking? In H3 creatures on water had no zone of control at all
|
||||
}
|
||||
|
||||
if(disembarking)
|
||||
{
|
||||
tmh.movePoints = h->movementPointsAfterEmbark(h->movement, cost, true);
|
||||
tmh.movePoints = h->movementPointsAfterEmbark(h->movement, cost, true, ti);
|
||||
return doMove(TryMoveHero::DISEMBARK, CHECK_FOR_GUARDS, VISIT_DEST, LEAVING_TILE);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user