mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
* half-working boots of levitation and angel's wings
This commit is contained in:
parent
70fa697f8b
commit
edd31ef41b
@ -1961,7 +1961,7 @@ void CAdvMapInt::tileHovered(const int3 &tile)
|
|||||||
}
|
}
|
||||||
else //no objs
|
else //no objs
|
||||||
{
|
{
|
||||||
if(accessible)
|
if(accessible && pnode->accessible != CGPathNode::FLYABLE)
|
||||||
{
|
{
|
||||||
if (guardingCreature) {
|
if (guardingCreature) {
|
||||||
CGI->curh->changeGraphic(0, 5 + turns*6);
|
CGI->curh->changeGraphic(0, 5 + turns*6);
|
||||||
|
@ -969,6 +969,11 @@ void CPlayerInterface::heroBonusChanged( const CGHeroInstance *hero, const Bonus
|
|||||||
if(bonus.type == Bonus::NONE) return;
|
if(bonus.type == Bonus::NONE) return;
|
||||||
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
boost::unique_lock<boost::recursive_mutex> un(*pim);
|
||||||
updateInfo(hero);
|
updateInfo(hero);
|
||||||
|
if (bonus.type == Bonus::FLYING_MOVEMENT || bonus.type == Bonus::WATER_WALKING && !gain)
|
||||||
|
{
|
||||||
|
//recalculate paths because hero has lost bonus influencing pathfinding
|
||||||
|
cb->recalculatePaths();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version )
|
template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, const int version )
|
||||||
|
@ -479,7 +479,7 @@ void CArtHandler::addBonuses()
|
|||||||
|
|
||||||
giveArtBonus(70,Bonus::LAND_MOVEMENT,+300);//Equestrian's Gloves
|
giveArtBonus(70,Bonus::LAND_MOVEMENT,+300);//Equestrian's Gloves
|
||||||
giveArtBonus(71,Bonus::SEA_MOVEMENT,+1000);//Necklace of Ocean Guidance
|
giveArtBonus(71,Bonus::SEA_MOVEMENT,+1000);//Necklace of Ocean Guidance
|
||||||
giveArtBonus(72,Bonus::FLYING_MOVEMENT,+1);//Angel Wings
|
giveArtBonus(72,Bonus::FLYING_MOVEMENT, 0, 1);//Angel Wings
|
||||||
|
|
||||||
giveArtBonus(73,Bonus::MANA_REGENERATION,+1);//Charm of Mana
|
giveArtBonus(73,Bonus::MANA_REGENERATION,+1);//Charm of Mana
|
||||||
giveArtBonus(74,Bonus::MANA_REGENERATION,+2);//Talisman of Mana
|
giveArtBonus(74,Bonus::MANA_REGENERATION,+2);//Talisman of Mana
|
||||||
@ -503,7 +503,7 @@ void CArtHandler::addBonuses()
|
|||||||
giveArtBonus(88,Bonus::WATER_SPELLS,0);//Tome of Water Magic
|
giveArtBonus(88,Bonus::WATER_SPELLS,0);//Tome of Water Magic
|
||||||
giveArtBonus(89,Bonus::EARTH_SPELLS,0);//Tome of Earth Magic
|
giveArtBonus(89,Bonus::EARTH_SPELLS,0);//Tome of Earth Magic
|
||||||
|
|
||||||
giveArtBonus(90,Bonus::WATER_WALKING,0);//Boots of Levitation
|
giveArtBonus(90,Bonus::WATER_WALKING, 0, 1);//Boots of Levitation
|
||||||
giveArtBonus(91,Bonus::NO_SHOTING_PENALTY,0);//Golden Bow
|
giveArtBonus(91,Bonus::NO_SHOTING_PENALTY,0);//Golden Bow
|
||||||
giveArtBonus(92,Bonus::SPELL_IMMUNITY,35);//Sphere of Permanence
|
giveArtBonus(92,Bonus::SPELL_IMMUNITY,35);//Sphere of Permanence
|
||||||
giveArtBonus(93,Bonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability
|
giveArtBonus(93,Bonus::NEGATE_ALL_NATURAL_IMMUNITIES,0);//Orb of Vulnerability
|
||||||
|
@ -573,15 +573,16 @@ si32 CGHeroInstance::manaLimit() const
|
|||||||
|
|
||||||
bool CGHeroInstance::canWalkOnSea() const
|
bool CGHeroInstance::canWalkOnSea() const
|
||||||
{
|
{
|
||||||
//TODO: write it - it should check if hero is flying, or something similar
|
return hasBonusOfType(Bonus::FLYING_MOVEMENT) || hasBonusOfType(Bonus::WATER_WALKING);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGHeroInstance::getPrimSkillLevel(int id) const
|
int CGHeroInstance::getPrimSkillLevel(int id) const
|
||||||
{
|
{
|
||||||
int ret = valOfBonuses(Bonus::PRIMARY_SKILL, id);
|
int ret = valOfBonuses(Bonus::PRIMARY_SKILL, id);
|
||||||
amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge
|
amax(ret, id/2); //minimal value is 0 for attack and defense and 1 for spell power and knowledge
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
|
ui8 CGHeroInstance::getSecSkillLevel(const int & ID) const
|
||||||
{
|
{
|
||||||
for(size_t i=0; i < secSkills.size(); ++i)
|
for(size_t i=0; i < secSkills.size(); ++i)
|
||||||
|
@ -1771,8 +1771,8 @@ void CGameState::getNeighbours( const TerrainTile &srct, int3 tile, std::vector<
|
|||||||
|
|
||||||
const TerrainTile &hlpt = map->getTile(hlp);
|
const TerrainTile &hlpt = map->getTile(hlp);
|
||||||
|
|
||||||
if((indeterminate(onLand) || onLand == (hlpt.tertype!=8) )
|
if((indeterminate(onLand) || onLand == (hlpt.tertype!=TerrainTile::water) )
|
||||||
&& hlpt.tertype!=9)
|
&& hlpt.tertype != TerrainTile::rock)
|
||||||
{
|
{
|
||||||
vec.push_back(hlp);
|
vec.push_back(hlp);
|
||||||
}
|
}
|
||||||
@ -1790,6 +1790,23 @@ int CGameState::getMovementCost(const CGHeroInstance *h, const int3 &src, const
|
|||||||
//get basic cost
|
//get basic cost
|
||||||
int ret = h->getTileCost(d,s);
|
int ret = h->getTileCost(d,s);
|
||||||
|
|
||||||
|
if(d.blocked)
|
||||||
|
{
|
||||||
|
bool freeFlying = h->getBonusesCount(Selector::typeSybtype(Bonus::FLYING_MOVEMENT, 1)) > 0;
|
||||||
|
|
||||||
|
if(!freeFlying)
|
||||||
|
{
|
||||||
|
ret *= 1.4f; //40% penalty for movement over blocked tile
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (d.tertype == TerrainTile::water)
|
||||||
|
{
|
||||||
|
if (!h->boat && h->getBonusesCount(Selector::typeSybtype(Bonus::WATER_WALKING, 1)) > 0)
|
||||||
|
{
|
||||||
|
ret *= 1.4f; //40% penalty for water walking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(src.x != dest.x && src.y != dest.y) //it's diagonal move
|
if(src.x != dest.x && src.y != dest.y) //it's diagonal move
|
||||||
{
|
{
|
||||||
int old = ret;
|
int old = ret;
|
||||||
@ -2104,6 +2121,9 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
|
|||||||
|
|
||||||
const std::vector<std::vector<std::vector<ui8> > > &FoW = getPlayer(hero->tempOwner)->fogOfWarMap;
|
const std::vector<std::vector<std::vector<ui8> > > &FoW = getPlayer(hero->tempOwner)->fogOfWarMap;
|
||||||
|
|
||||||
|
bool flying = hero->hasBonusOfType(Bonus::FLYING_MOVEMENT);
|
||||||
|
bool waterWalk = hero->hasBonusOfType(Bonus::WATER_WALKING);
|
||||||
|
|
||||||
//graph initialization
|
//graph initialization
|
||||||
CGPathNode ***graph = out.nodes;
|
CGPathNode ***graph = out.nodes;
|
||||||
for(size_t i=0; i < out.sizes.x; ++i)
|
for(size_t i=0; i < out.sizes.x; ++i)
|
||||||
@ -2115,7 +2135,11 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
|
|||||||
const TerrainTile *tinfo = &map->terrain[i][j][k];
|
const TerrainTile *tinfo = &map->terrain[i][j][k];
|
||||||
CGPathNode &node = graph[i][j][k];
|
CGPathNode &node = graph[i][j][k];
|
||||||
|
|
||||||
node.accessible = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
|
node.accessible = (tinfo->blocked ? CGPathNode::FLYABLE : CGPathNode::ACCESSIBLE);
|
||||||
|
if(!flying && node.accessible == CGPathNode::FLYABLE)
|
||||||
|
{
|
||||||
|
node.accessible = CGPathNode::BLOCKED;
|
||||||
|
}
|
||||||
node.turns = 0xff;
|
node.turns = 0xff;
|
||||||
node.moveRemains = 0;
|
node.moveRemains = 0;
|
||||||
node.coord.x = i;
|
node.coord.x = i;
|
||||||
@ -2124,9 +2148,20 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
|
|||||||
node.land = tinfo->tertype != TerrainTile::water;
|
node.land = tinfo->tertype != TerrainTile::water;
|
||||||
node.theNodeBefore = NULL;
|
node.theNodeBefore = NULL;
|
||||||
|
|
||||||
|
if((onLand || indeterminate(onLand)) && !node.land)//it's sea and we cannot walk on sea
|
||||||
|
{
|
||||||
|
if (waterWalk || flying)
|
||||||
|
{
|
||||||
|
node.accessible = CGPathNode::FLYABLE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node.accessible = CGPathNode::BLOCKED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( tinfo->tertype == TerrainTile::rock//it's rock
|
if ( tinfo->tertype == TerrainTile::rock//it's rock
|
||||||
|| onLand && !node.land //it's sea and we cannot walk on sea
|
|| !onLand && node.land //it's land and we cannot walk on land (complementary condition is handled above)
|
||||||
|| !onLand && node.land //it's land and we cannot walk on land
|
|
||||||
|| !FoW[i][j][k] //tile is covered by the FoW
|
|| !FoW[i][j][k] //tile is covered by the FoW
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -2185,7 +2220,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
|
|||||||
std::queue<CGPathNode*> mq;
|
std::queue<CGPathNode*> mq;
|
||||||
mq.push(&graph[src.x][src.y][src.z]);
|
mq.push(&graph[src.x][src.y][src.z]);
|
||||||
|
|
||||||
ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
|
//ui32 curDist = 0xffffffff; //total cost of path - init with max possible val
|
||||||
|
|
||||||
std::vector<int3> neighbours;
|
std::vector<int3> neighbours;
|
||||||
neighbours.reserve(8);
|
neighbours.reserve(8);
|
||||||
@ -2248,7 +2283,7 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int
|
|||||||
const bool guardedNeighbor = guardingCreaturePosition(dp.coord) != int3(-1, -1, -1);
|
const bool guardedNeighbor = guardingCreaturePosition(dp.coord) != int3(-1, -1, -1);
|
||||||
const bool positionIsGuard = guardingCreaturePosition(cp->coord) == cp->coord;
|
const bool positionIsGuard = guardingCreaturePosition(cp->coord) == cp->coord;
|
||||||
|
|
||||||
if (dp.accessible == CGPathNode::ACCESSIBLE
|
if (dp.accessible == CGPathNode::ACCESSIBLE || dp.accessible == CGPathNode::FLYABLE
|
||||||
|| (guardedNeighbor && !positionIsGuard)) // Can step into a hostile tile once.
|
|| (guardedNeighbor && !positionIsGuard)) // Can step into a hostile tile once.
|
||||||
{
|
{
|
||||||
mq.push(&dp);
|
mq.push(&dp);
|
||||||
@ -3651,13 +3686,33 @@ bool CPathsInfo::getPath( const int3 &dst, CGPath &out )
|
|||||||
{
|
{
|
||||||
out.nodes.clear();
|
out.nodes.clear();
|
||||||
const CGPathNode *curnode = &nodes[dst.x][dst.y][dst.z];
|
const CGPathNode *curnode = &nodes[dst.x][dst.y][dst.z];
|
||||||
if(!curnode->theNodeBefore)
|
if(!curnode->theNodeBefore || curnode->accessible == CGPathNode::FLYABLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
//we'll transform number of turns to conform the rule that hero cannot stop on blocked tile
|
||||||
|
bool transition01 = false;
|
||||||
while(curnode)
|
while(curnode)
|
||||||
{
|
{
|
||||||
out.nodes.push_back(*curnode);
|
CGPathNode cpn = *curnode;
|
||||||
|
if(transition01)
|
||||||
|
{
|
||||||
|
if (curnode->accessible == CGPathNode::ACCESSIBLE)
|
||||||
|
{
|
||||||
|
transition01 = false;
|
||||||
|
}
|
||||||
|
else if (curnode->accessible == CGPathNode::FLYABLE)
|
||||||
|
{
|
||||||
|
cpn.turns = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(curnode->turns == 1 && curnode->theNodeBefore->turns == 0)
|
||||||
|
{
|
||||||
|
transition01 = true;
|
||||||
|
}
|
||||||
curnode = curnode->theNodeBefore;
|
curnode = curnode->theNodeBefore;
|
||||||
|
|
||||||
|
out.nodes.push_back(cpn);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,8 @@ struct CGPathNode
|
|||||||
ACCESSIBLE=1, //tile can be entered and passed
|
ACCESSIBLE=1, //tile can be entered and passed
|
||||||
VISITABLE, //tile can be entered as the last tile in path
|
VISITABLE, //tile can be entered as the last tile in path
|
||||||
BLOCKVIS, //visitable from neighbouring tile but not passable
|
BLOCKVIS, //visitable from neighbouring tile but not passable
|
||||||
BLOCKED //tile can't be entered nor visited
|
BLOCKED, //tile can't be entered nor visited
|
||||||
|
FLYABLE //if hero flies, he can pass this tile
|
||||||
};
|
};
|
||||||
|
|
||||||
ui8 accessible; //the enum above
|
ui8 accessible; //the enum above
|
||||||
|
@ -50,14 +50,14 @@ namespace PrimarySkill
|
|||||||
BONUS_NAME(SECONDARY_SKILL_PREMY) /*%*/ \
|
BONUS_NAME(SECONDARY_SKILL_PREMY) /*%*/ \
|
||||||
BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \
|
BONUS_NAME(SURRENDER_DISCOUNT) /*%*/ \
|
||||||
BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted to this part*/ \
|
BONUS_NAME(STACKS_SPEED) /*additional info - percent of speed bonus applied after direct bonuses; >0 - added, <0 - substracted to this part*/ \
|
||||||
BONUS_NAME(FLYING_MOVEMENT) \
|
BONUS_NAME(FLYING_MOVEMENT) /*subtype 1 - without penalty, 2 - with penalty*/ \
|
||||||
BONUS_NAME(SPELL_DURATION) \
|
BONUS_NAME(SPELL_DURATION) \
|
||||||
BONUS_NAME(AIR_SPELL_DMG_PREMY) \
|
BONUS_NAME(AIR_SPELL_DMG_PREMY) \
|
||||||
BONUS_NAME(EARTH_SPELL_DMG_PREMY) \
|
BONUS_NAME(EARTH_SPELL_DMG_PREMY) \
|
||||||
BONUS_NAME(FIRE_SPELL_DMG_PREMY) \
|
BONUS_NAME(FIRE_SPELL_DMG_PREMY) \
|
||||||
BONUS_NAME(WATER_SPELL_DMG_PREMY) \
|
BONUS_NAME(WATER_SPELL_DMG_PREMY) \
|
||||||
BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \
|
BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \
|
||||||
BONUS_NAME(WATER_WALKING) \
|
BONUS_NAME(WATER_WALKING) /*subtype 1 - without penalty, 2 - with penalty*/ \
|
||||||
BONUS_NAME(NO_SHOTING_PENALTY) \
|
BONUS_NAME(NO_SHOTING_PENALTY) \
|
||||||
BONUS_NAME(DISPEL_IMMUNITY) \
|
BONUS_NAME(DISPEL_IMMUNITY) \
|
||||||
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
|
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
|
||||||
|
@ -1591,7 +1591,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
|
|||||||
}
|
}
|
||||||
|
|
||||||
TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z];
|
TerrainTile t = gs->map->terrain[hmpos.x][hmpos.y][hmpos.z];
|
||||||
int cost = gs->getMovementCost(h,h->getPosition(false),CGHeroInstance::convertPosition(dst,false),h->movement);
|
int cost = gs->getMovementCost(h, h->getPosition(false), CGHeroInstance::convertPosition(dst,false),h->movement);
|
||||||
|
|
||||||
//result structure for start - movement failed, no move points used
|
//result structure for start - movement failed, no move points used
|
||||||
TryMoveHero tmh;
|
TryMoveHero tmh;
|
||||||
@ -1605,7 +1605,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
|
|||||||
|
|
||||||
//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)
|
||||||
if((t.tertype == TerrainTile::rock || (t.blocked && !t.visitable))
|
if((t.tertype == TerrainTile::rock || (t.blocked && !t.visitable && !h->hasBonusOfType(Bonus::FLYING_MOVEMENT) ))
|
||||||
&& complain("Cannot move hero, destination tile is blocked!")
|
&& complain("Cannot move hero, destination tile is blocked!")
|
||||||
|| (!h->boat && !h->canWalkOnSea() && t.tertype == TerrainTile::water && (t.visitableObjects.size() != 1 || (t.visitableObjects.front()->ID != 8 && t.visitableObjects.front()->ID != HEROI_TYPE))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land)
|
|| (!h->boat && !h->canWalkOnSea() && t.tertype == TerrainTile::water && (t.visitableObjects.size() != 1 || (t.visitableObjects.front()->ID != 8 && t.visitableObjects.front()->ID != HEROI_TYPE))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land)
|
||||||
&& complain("Cannot move hero, destination tile is on water!")
|
&& complain("Cannot move hero, destination tile is on water!")
|
||||||
@ -1647,7 +1647,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255*
|
|||||||
//checks for standard movement
|
//checks for standard movement
|
||||||
if(!instant)
|
if(!instant)
|
||||||
{
|
{
|
||||||
if( distance(h->pos,dst) >= 1.5 && complain("Tiles are not neighbouring!")
|
if( distance(h->pos,dst) >= 1.5 && complain("Tiles are not neighboring!")
|
||||||
|| h->movement < cost && h->movement < 100 && complain("Not enough move points!"))
|
|| h->movement < cost && h->movement < 100 && complain("Not enough move points!"))
|
||||||
{
|
{
|
||||||
sendAndApply(&tmh);
|
sendAndApply(&tmh);
|
||||||
@ -4455,12 +4455,30 @@ bool CGameHandler::castSpell(const CGHeroInstance *h, int spellID, const int3 &p
|
|||||||
sendAndApply(&tmh);
|
sendAndApply(&tmh);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case FLY: //Fly
|
||||||
|
{
|
||||||
|
int subtype = schoolLevel >= 2 ? 1 : 2; //adv or expert
|
||||||
|
|
||||||
|
GiveBonus gb;
|
||||||
|
gb.id = h->id;
|
||||||
|
gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::FLYING_MOVEMENT, Bonus::CASTED_SPELL, 0, Spells::FLY, subtype);
|
||||||
|
sendAndApply(&gb);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WATER_WALK: //Water Walk
|
||||||
|
{
|
||||||
|
int subtype = schoolLevel >= 2 ? 1 : 2; //adv or expert
|
||||||
|
|
||||||
|
GiveBonus gb;
|
||||||
|
gb.id = h->id;
|
||||||
|
gb.bonus = Bonus(Bonus::ONE_DAY, Bonus::WATER_WALKING, Bonus::CASTED_SPELL, 0, Spells::FLY, subtype);
|
||||||
|
sendAndApply(&gb);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case VISIONS: //Visions
|
case VISIONS: //Visions
|
||||||
case VIEW_EARTH: //View Earth
|
case VIEW_EARTH: //View Earth
|
||||||
case DISGUISE: //Disguise
|
case DISGUISE: //Disguise
|
||||||
case VIEW_AIR: //View Air
|
case VIEW_AIR: //View Air
|
||||||
case FLY: //Fly
|
|
||||||
case WATER_WALK: //Water Walk
|
|
||||||
case TOWN_PORTAL: //Town Portal
|
case TOWN_PORTAL: //Town Portal
|
||||||
default:
|
default:
|
||||||
COMPLAIN_RET("This spell is not implemented yet!");
|
COMPLAIN_RET("This spell is not implemented yet!");
|
||||||
|
Loading…
Reference in New Issue
Block a user