1
0
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:
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);
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;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);
}