1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +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:
ArseniyShestakov 2015-11-12 14:04:33 +03:00
parent 9ed9d94009
commit abc4ea272f
5 changed files with 77 additions and 58 deletions

View File

@ -50,11 +50,11 @@ CPathfinder::CPathfinder(CPathsInfo & _out, CGameState * _gs, const CGHeroInstan
} }
hlp = make_unique<CPathfinderHelper>(hero); hlp = make_unique<CPathfinderHelper>(hero);
if(hlp->ti->bonusFlying) if(hlp->hasBonusOfType(Bonus::FLYING_MOVEMENT))
options.useFlying = true; options.useFlying = true;
if(hlp->ti->bonusWaterWalking) if(hlp->hasBonusOfType(Bonus::WATER_WALKING))
options.useWaterWalking = true; options.useWaterWalking = true;
if(CGWhirlpool::isProtected(hero)) if(hlp->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
options.useTeleportWhirlpool = true; options.useTeleportWhirlpool = true;
initializeGraph(); initializeGraph();
@ -109,7 +109,7 @@ void CPathfinder::calculatePaths()
if(!movement) if(!movement)
{ {
hlp->updateTurnInfo(++turn); hlp->updateTurnInfo(++turn);
movement = hlp->getMaxMovePoints(cp->layer, turn); movement = hlp->getMaxMovePoints(cp->layer);
} }
//add accessible neighbouring nodes to the queue //add accessible neighbouring nodes to the queue
@ -140,11 +140,11 @@ void CPathfinder::calculatePaths()
continue; continue;
destAction = getDestAction(); 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; int remains = movement - cost;
if(destAction == CGPathNode::EMBARK || destAction == CGPathNode::DISEMBARK) 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; cost = movement - remains;
} }
int turnAtNextTile = turn; int turnAtNextTile = turn;
@ -152,8 +152,8 @@ void CPathfinder::calculatePaths()
{ {
//occurs rarely, when hero with low movepoints tries to leave the road //occurs rarely, when hero with low movepoints tries to leave the road
hlp->updateTurnInfo(++turnAtNextTile); hlp->updateTurnInfo(++turnAtNextTile);
int moveAtNextTile = hlp->getMaxMovePoints(i, turnAtNextTile); int moveAtNextTile = hlp->getMaxMovePoints(i);
cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile, hlp->getTurnInfo(turnAtNextTile)); //cost must be updated, movement points changed :( cost = CPathfinderHelper::getMovementCost(hero, cp->coord, dp->coord, moveAtNextTile, hlp->getTurnInfo()); //cost must be updated, movement points changed :(
remains = moveAtNextTile - cost; remains = moveAtNextTile - cost;
} }
@ -285,13 +285,13 @@ bool CPathfinder::isLayerAvailable(const ELayer layer, const int turn) const
switch(layer) switch(layer)
{ {
case ELayer::AIR: case ELayer::AIR:
if(!hlp->ti->bonusFlying) if(!hlp->hasBonusOfType(Bonus::FLYING_MOVEMENT))
return false; return false;
break; break;
case ELayer::WATER: case ELayer::WATER:
if(!hlp->ti->bonusWaterWalking) if(!hlp->hasBonusOfType(Bonus::WATER_WALKING))
return false; return false;
break; break;
@ -701,47 +701,63 @@ bool CPathfinder::canVisitObject() const
return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL; return cp->layer == ELayer::LAND || cp->layer == ELayer::SAIL;
} }
TurnInfo::TurnInfo(const CGHeroInstance * h, const int Turn) TurnInfo::TurnInfo(const CGHeroInstance * Hero, const int turn)
: turn(Turn) : hero(Hero), maxMovePointsLand(-1), maxMovePointsWater(-1)
{ {
maxMovePointsLand = h->maxMovePoints(true); bonuses = hero->getAllBonuses(Selector::days(turn), nullptr);
maxMovePointsWater = h->maxMovePoints(false); }
bonusFlying = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT, turn);
bonusWaterWalking = h->getBonusAtTurn(Bonus::WATER_WALKING, turn); 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 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; return layer == EPathfindingLayer::SAIL ? maxMovePointsWater : maxMovePointsLand;
} }
CPathfinderHelper::CPathfinderHelper(const CGHeroInstance * Hero) CPathfinderHelper::CPathfinderHelper(const CGHeroInstance * Hero)
: ti(nullptr), hero(Hero) : turn(0), hero(Hero)
{ {
turnsInfo.reserve(16); turnsInfo.reserve(16);
updateTurnInfo(); 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()) turn = Turn;
ti = turnsInfo[turn]; if(turn >= turnsInfo.size())
else
{ {
ti = new TurnInfo(hero, turn); auto ti = new TurnInfo(hero, turn);
turnsInfo.push_back(ti); turnsInfo.push_back(ti);
} }
} }
} }
const TurnInfo * CPathfinderHelper::getTurnInfo(const int turn) const const TurnInfo * CPathfinderHelper::getTurnInfo() const
{ {
return turnsInfo[turn]; 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); 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); auto s = h->cb->getTile(src), d = h->cb->getTile(dst);
int ret = h->getTileCost(*d, *s, ti); 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) else if(d->terType == ETerrainType::WATER)
{ {
if(h->boat && s->hasFavourableWinds() && d->hasFavourableWinds()) //Favourable Winds if(h->boat && s->hasFavourableWinds() && d->hasFavourableWinds()) //Favourable Winds
ret *= 0.666; 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;
} }
} }

View File

@ -192,28 +192,30 @@ private:
}; };
struct TurnInfo struct DLL_LINKAGE TurnInfo
{ {
int turn; const CGHeroInstance * hero;
int maxMovePointsLand; TBonusListPtr bonuses;
int maxMovePointsWater; mutable int maxMovePointsLand;
const Bonus * bonusFlying; mutable int maxMovePointsWater;
const Bonus * bonusWaterWalking;
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; int getMaxMovePoints(const EPathfindingLayer layer) const;
}; };
class DLL_LINKAGE CPathfinderHelper class DLL_LINKAGE CPathfinderHelper
{ {
public: public:
TurnInfo * ti; int turn;
const CGHeroInstance * hero; const CGHeroInstance * hero;
CPathfinderHelper(const CGHeroInstance * Hero); CPathfinderHelper(const CGHeroInstance * Hero);
void updateTurnInfo(const int turn = 0); void updateTurnInfo(const int turn = 0);
const TurnInfo * getTurnInfo(const int turn) const; const TurnInfo * getTurnInfo() const;
int getMaxMovePoints(const EPathfindingLayer layer, const int turn) 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); static void getNeighbours(CGameState * gs, const TerrainTile & srct, const int3 & tile, std::vector<int3> & vec, const boost::logic::tribool & onLand, const bool limitCoastSailing);

View File

@ -80,7 +80,7 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile &dest, const TerrainTile &fro
break; 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. // 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. // 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 ui8 CGHeroInstance::getSecSkillLevel(SecondarySkill skill) const
{ {
for(auto & elem : secSkills) for(auto & elem : secSkills)
@ -176,8 +171,11 @@ bool CGHeroInstance::canLearnSkill() const
return secSkills.size() < GameConstants::SKILL_PER_HERO; 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; int base;
if(onLand) if(onLand)
@ -196,10 +194,10 @@ int CGHeroInstance::maxMovePoints(bool onLand) const
} }
const Bonus::BonusType bt = onLand ? Bonus::LAND_MOVEMENT : Bonus::SEA_MOVEMENT; 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 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; return int(base* (1+modifier)) + bonus;
} }
@ -1166,9 +1164,12 @@ CBonusSystemNode * CGHeroInstance::whereShouldBeAttached(CGameState *gs)
return CArmedInstance::whereShouldBeAttached(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 (MPsBefore - basicCost) * static_cast<double>(maxMovePoints(disembark)) / maxMovePoints(!disembark);
return 0; //take all MPs otherwise return 0; //take all MPs otherwise

View File

@ -134,7 +134,6 @@ public:
ui32 getLowestCreatureSpeed() const; ui32 getLowestCreatureSpeed() const;
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation' 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 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 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 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 setSecSkillLevel(SecondarySkill which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
void levelUp(std::vector<SecondarySkill> skills); void levelUp(std::vector<SecondarySkill> skills);
int maxMovePoints(bool onLand) const; int maxMovePoints(bool onLand, const TurnInfo * ti = nullptr) const;
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) 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 static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
double getFightingStrength() const; // takes attack / defense skill into account double getFightingStrength() const; // takes attack / defense skill into account

View File

@ -1778,9 +1778,10 @@ bool CGameHandler::moveHero( ObjectInstanceID hid, int3 dst, ui8 teleporting, bo
tmh.movePoints = h->movement; tmh.movePoints = h->movement;
//check if destination tile is available //check if destination tile is available
const bool canFly = h->getBonusAtTurn(Bonus::FLYING_MOVEMENT); auto ti = new TurnInfo(h);
const bool canWalkOnSea = h->getBonusAtTurn(Bonus::WATER_WALKING); const bool canFly = ti->hasBonusOfType(Bonus::FLYING_MOVEMENT);
const int cost = CPathfinderHelper::getMovementCost(h, h->getPosition(), hmpos, h->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 //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) //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) 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); 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 //attack guards on embarking? In H3 creatures on water had no zone of control at all
} }
if(disembarking) 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); return doMove(TryMoveHero::DISEMBARK, CHECK_FOR_GUARDS, VISIT_DEST, LEAVING_TILE);
} }