mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merge pull request #2030 from Nordsoft91/boats
This commit is contained in:
commit
a553a4aa66
@ -864,7 +864,7 @@ void AINodeStorage::setHeroes(std::map<const CGHeroInstance *, HeroRole> heroes)
|
|||||||
|
|
||||||
if(actor->hero->tempOwner != ai->playerID)
|
if(actor->hero->tempOwner != ai->playerID)
|
||||||
{
|
{
|
||||||
bool onLand = !actor->hero->boat;
|
bool onLand = !actor->hero->boat || actor->hero->boat->layer != EPathfindingLayer::SAIL;
|
||||||
actor->initialMovement = actor->hero->maxMovePoints(onLand);
|
actor->initialMovement = actor->hero->maxMovePoints(onLand);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ ChainActor::ChainActor(const CGHeroInstance * hero, HeroRole heroRole, uint64_t
|
|||||||
baseActor(this), carrierParent(nullptr), otherParent(nullptr), actorExchangeCount(1), armyCost(), actorAction()
|
baseActor(this), carrierParent(nullptr), otherParent(nullptr), actorExchangeCount(1), armyCost(), actorAction()
|
||||||
{
|
{
|
||||||
initialPosition = hero->visitablePos();
|
initialPosition = hero->visitablePos();
|
||||||
layer = hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND;
|
layer = hero->boat ? hero->boat->layer : EPathfindingLayer::LAND;
|
||||||
initialMovement = hero->movement;
|
initialMovement = hero->movement;
|
||||||
initialTurn = 0;
|
initialTurn = 0;
|
||||||
armyValue = hero->getArmyStrength();
|
armyValue = hero->getArmyStrength();
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "../../lib/RoadHandler.h"
|
#include "../../lib/RoadHandler.h"
|
||||||
#include "../../lib/TerrainHandler.h"
|
#include "../../lib/TerrainHandler.h"
|
||||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||||
|
#include "../../lib/mapObjects/MiscObjects.h"
|
||||||
#include "../../lib/mapping/CMap.h"
|
#include "../../lib/mapping/CMap.h"
|
||||||
|
|
||||||
struct NeighborTilesInfo
|
struct NeighborTilesInfo
|
||||||
@ -394,15 +395,11 @@ std::shared_ptr<CAnimation> MapRendererObjects::getBaseAnimation(const CGObjectI
|
|||||||
|
|
||||||
bool generateMovementGroups = (info->id == Obj::BOAT) || (info->id == Obj::HERO);
|
bool generateMovementGroups = (info->id == Obj::BOAT) || (info->id == Obj::HERO);
|
||||||
|
|
||||||
//TODO: relocate to config file?
|
|
||||||
// Boat appearance files only contain single, unanimated image
|
// Boat appearance files only contain single, unanimated image
|
||||||
// proper boat animations are actually in different file
|
// proper boat animations are actually in different file
|
||||||
static const std::vector<std::string> boatAnimations = {
|
|
||||||
"AB01_.def", "AB02_.def", "AB03_.def"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (info->id == Obj::BOAT)
|
if (info->id == Obj::BOAT)
|
||||||
return getAnimation(boatAnimations[info->subid], generateMovementGroups);
|
if(auto boat = dynamic_cast<const CGBoat*>(obj); boat && !boat->actualAnimation.empty())
|
||||||
|
return getAnimation(boat->actualAnimation, generateMovementGroups);
|
||||||
|
|
||||||
return getAnimation(info->animationFile, generateMovementGroups);
|
return getAnimation(info->animationFile, generateMovementGroups);
|
||||||
}
|
}
|
||||||
@ -438,13 +435,6 @@ std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectI
|
|||||||
"AF00", "AF01", "AF02", "AF03", "AF04", "AF05", "AF06", "AF07"
|
"AF00", "AF01", "AF02", "AF03", "AF04", "AF05", "AF06", "AF07"
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: relocate to config file?
|
|
||||||
static const std::vector<std::vector<std::string>> boatFlags = {
|
|
||||||
{"ABF01L", "ABF01G", "ABF01R", "ABF01D", "ABF01B", "ABF01P", "ABF01W", "ABF01K"},
|
|
||||||
{"ABF02L", "ABF02G", "ABF02R", "ABF02D", "ABF02B", "ABF02P", "ABF02W", "ABF02K"},
|
|
||||||
{"ABF03L", "ABF03G", "ABF03R", "ABF03D", "ABF03B", "ABF03P", "ABF03W", "ABF03K"}
|
|
||||||
};
|
|
||||||
|
|
||||||
if(obj->ID == Obj::HERO)
|
if(obj->ID == Obj::HERO)
|
||||||
{
|
{
|
||||||
assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
|
assert(dynamic_cast<const CGHeroInstance *>(obj) != nullptr);
|
||||||
@ -455,12 +445,8 @@ std::shared_ptr<CAnimation> MapRendererObjects::getFlagAnimation(const CGObjectI
|
|||||||
if(obj->ID == Obj::BOAT)
|
if(obj->ID == Obj::BOAT)
|
||||||
{
|
{
|
||||||
const auto * boat = dynamic_cast<const CGBoat *>(obj);
|
const auto * boat = dynamic_cast<const CGBoat *>(obj);
|
||||||
assert(boat->subID < boatFlags.size());
|
if(boat && boat->hero && !boat->flagAnimations[boat->hero->tempOwner.getNum()].empty())
|
||||||
if (boat->hero)
|
return getAnimation(boat->flagAnimations[boat->hero->tempOwner.getNum()], true);
|
||||||
{
|
|
||||||
assert(boat->hero->tempOwner.isValidPlayer());
|
|
||||||
return getAnimation(boatFlags[boat->subID][boat->hero->tempOwner.getNum()], true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -470,15 +456,10 @@ std::shared_ptr<CAnimation> MapRendererObjects::getOverlayAnimation(const CGObje
|
|||||||
{
|
{
|
||||||
if(obj->ID == Obj::BOAT)
|
if(obj->ID == Obj::BOAT)
|
||||||
{
|
{
|
||||||
//TODO: relocate to config file?
|
|
||||||
// Boats have additional animation with waves around boat
|
// Boats have additional animation with waves around boat
|
||||||
static const std::vector<std::string> boatAnimations = {
|
|
||||||
"ABM01_.def", "ABM02_.def", "ABM03_.def"
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto * boat = dynamic_cast<const CGBoat *>(obj);
|
const auto * boat = dynamic_cast<const CGBoat *>(obj);
|
||||||
if (boat->hero)
|
if(boat && boat->hero && !boat->overlayAnimation.empty())
|
||||||
return getAnimation(boatAnimations[obj->subID], true);
|
return getAnimation(boat->overlayAnimation, true);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -1079,7 +1079,7 @@ void CExchangeWindow::updateWidgets()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CShipyardWindow::CShipyardWindow(const TResources & cost, int state, int boatType, const std::function<void()> & onBuy)
|
CShipyardWindow::CShipyardWindow(const TResources & cost, int state, BoatId boatType, const std::function<void()> & onBuy)
|
||||||
: CStatusbarWindow(PLAYER_COLORED, "TPSHIP")
|
: CStatusbarWindow(PLAYER_COLORED, "TPSHIP")
|
||||||
{
|
{
|
||||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||||
@ -1089,7 +1089,7 @@ CShipyardWindow::CShipyardWindow(const TResources & cost, int state, int boatTyp
|
|||||||
std::string boatFilenames[3] = {"AB01_", "AB02_", "AB03_"};
|
std::string boatFilenames[3] = {"AB01_", "AB02_", "AB03_"};
|
||||||
|
|
||||||
Point waterCenter = Point(bgWater->pos.x+bgWater->pos.w/2, bgWater->pos.y+bgWater->pos.h/2);
|
Point waterCenter = Point(bgWater->pos.x+bgWater->pos.w/2, bgWater->pos.y+bgWater->pos.h/2);
|
||||||
bgShip = std::make_shared<CAnimImage>(boatFilenames[boatType], 0, 7, 120, 96, 0);
|
bgShip = std::make_shared<CAnimImage>(boatFilenames[boatType.getNum()], 0, 7, 120, 96, 0);
|
||||||
bgShip->center(waterCenter);
|
bgShip->center(waterCenter);
|
||||||
|
|
||||||
// Create resource icons and costs.
|
// Create resource icons and costs.
|
||||||
|
@ -358,7 +358,7 @@ class CShipyardWindow : public CStatusbarWindow
|
|||||||
std::shared_ptr<CButton> quit;
|
std::shared_ptr<CButton> quit;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CShipyardWindow(const TResources & cost, int state, int boatType, const std::function<void()> & onBuy);
|
CShipyardWindow(const TResources & cost, int state, BoatId boatType, const std::function<void()> & onBuy);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Creature transformer window
|
/// Creature transformer window
|
||||||
|
@ -115,9 +115,35 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"types" : {
|
"types" : {
|
||||||
"evil" : { "index" : 0, "rmg" : { "mapLimit" : 64 } },
|
"evil" :
|
||||||
"good" : { "index" : 1, "rmg" : { "mapLimit" : 64 } },
|
{
|
||||||
"neutral" : { "index" : 2, "rmg" : { "mapLimit" : 64 } },
|
"index" : 0,
|
||||||
|
"layer" : "sail",
|
||||||
|
"actualAnimation" : "AB01_.def",
|
||||||
|
"overlayAnimation" : "ABM01_.def",
|
||||||
|
"onboardAssaultAllowed" : true,
|
||||||
|
"onboardVisitAllowed" : true,
|
||||||
|
"flagAnimations" : ["ABF01L", "ABF01G", "ABF01R", "ABF01D", "ABF01B", "ABF01P", "ABF01W", "ABF01K"]
|
||||||
|
},
|
||||||
|
"good" :
|
||||||
|
{
|
||||||
|
"index" : 1,
|
||||||
|
"layer" : "sail",
|
||||||
|
"actualAnimation" : "AB02_.def",
|
||||||
|
"overlayAnimation" : "ABM02_.def",
|
||||||
|
"onboardAssaultAllowed" : true,
|
||||||
|
"onboardVisitAllowed" : true,
|
||||||
|
"flagAnimations" : ["ABF02L", "ABF02G", "ABF02R", "ABF02D", "ABF02B", "ABF02P", "ABF02W", "ABF02K"]
|
||||||
|
},
|
||||||
|
"neutral" : {
|
||||||
|
"index" : 2,
|
||||||
|
"layer" : "sail",
|
||||||
|
"actualAnimation" : "AB03_.def",
|
||||||
|
"overlayAnimation" : "ABM03_.def",
|
||||||
|
"onboardAssaultAllowed" : true,
|
||||||
|
"onboardVisitAllowed" : true,
|
||||||
|
"flagAnimations" : ["ABF03L", "ABF03G", "ABF03R", "ABF03D", "ABF03B", "ABF03P", "ABF03W", "ABF03K"]
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@ void NodeStorage::resetTile(const int3 & tile, const EPathfindingLayer & layer,
|
|||||||
|
|
||||||
std::vector<CGPathNode *> NodeStorage::getInitialNodes()
|
std::vector<CGPathNode *> NodeStorage::getInitialNodes()
|
||||||
{
|
{
|
||||||
auto * initialNode = getNode(out.hpos, out.hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND);
|
auto * initialNode = getNode(out.hpos, out.hero->boat ? out.hero->boat->layer : EPathfindingLayer::LAND);
|
||||||
|
|
||||||
initialNode->turns = 0;
|
initialNode->turns = 0;
|
||||||
initialNode->moveRemains = out.hero->movement;
|
initialNode->moveRemains = out.hero->movement;
|
||||||
@ -1019,12 +1019,18 @@ bool TurnInfo::isLayerAvailable(const EPathfindingLayer & layer) const
|
|||||||
switch(layer)
|
switch(layer)
|
||||||
{
|
{
|
||||||
case EPathfindingLayer::AIR:
|
case EPathfindingLayer::AIR:
|
||||||
|
if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::AIR)
|
||||||
|
break;
|
||||||
|
|
||||||
if(!hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
if(!hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EPathfindingLayer::WATER:
|
case EPathfindingLayer::WATER:
|
||||||
|
if(hero && hero->boat && hero->boat->layer == EPathfindingLayer::WATER)
|
||||||
|
break;
|
||||||
|
|
||||||
if(!hasBonusOfType(Bonus::WATER_WALKING))
|
if(!hasBonusOfType(Bonus::WATER_WALKING))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -1236,23 +1242,25 @@ int CPathfinderHelper::getMovementCost(
|
|||||||
|
|
||||||
bool isSailLayer;
|
bool isSailLayer;
|
||||||
if(indeterminate(isDstSailLayer))
|
if(indeterminate(isDstSailLayer))
|
||||||
isSailLayer = hero->boat != nullptr && dt->terType->isWater();
|
isSailLayer = hero->boat && hero->boat->layer == EPathfindingLayer::SAIL && dt->terType->isWater();
|
||||||
else
|
else
|
||||||
isSailLayer = static_cast<bool>(isDstSailLayer);
|
isSailLayer = static_cast<bool>(isDstSailLayer);
|
||||||
|
|
||||||
bool isWaterLayer;
|
bool isWaterLayer;
|
||||||
if(indeterminate(isDstWaterLayer))
|
if(indeterminate(isDstWaterLayer))
|
||||||
isWaterLayer = dt->terType->isWater();
|
isWaterLayer = ((hero->boat && hero->boat->layer == EPathfindingLayer::WATER) || ti->hasBonusOfType(Bonus::WATER_WALKING)) && dt->terType->isWater();
|
||||||
else
|
else
|
||||||
isWaterLayer = static_cast<bool>(isDstWaterLayer);
|
isWaterLayer = static_cast<bool>(isDstWaterLayer);
|
||||||
|
|
||||||
|
bool isAirLayer = (hero->boat && hero->boat->layer == EPathfindingLayer::AIR) || ti->hasBonusOfType(Bonus::FLYING_MOVEMENT);
|
||||||
|
|
||||||
int ret = hero->getTileCost(*dt, *ct, ti);
|
int ret = hero->getTileCost(*dt, *ct, ti);
|
||||||
if(isSailLayer)
|
if(isSailLayer)
|
||||||
{
|
{
|
||||||
if(ct->hasFavorableWinds())
|
if(ct->hasFavorableWinds())
|
||||||
ret = static_cast<int>(ret * 2.0 / 3);
|
ret = static_cast<int>(ret * 2.0 / 3);
|
||||||
}
|
}
|
||||||
else if(ti->hasBonusOfType(Bonus::FLYING_MOVEMENT))
|
else if(isAirLayer)
|
||||||
vstd::amin(ret, GameConstants::BASE_MOVEMENT_COST + ti->valOfBonuses(Bonus::FLYING_MOVEMENT));
|
vstd::amin(ret, GameConstants::BASE_MOVEMENT_COST + ti->valOfBonuses(Bonus::FLYING_MOVEMENT));
|
||||||
else if(isWaterLayer && ti->hasBonusOfType(Bonus::WATER_WALKING))
|
else if(isWaterLayer && ti->hasBonusOfType(Bonus::WATER_WALKING))
|
||||||
ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(Bonus::WATER_WALKING)) / 100.0);
|
ret = static_cast<int>(ret * (100.0 + ti->valOfBonuses(Bonus::WATER_WALKING)) / 100.0);
|
||||||
|
@ -1241,6 +1241,16 @@ class BattleField : public BaseForID<BattleField, si32>
|
|||||||
DLL_LINKAGE static BattleField fromString(const std::string & identifier);
|
DLL_LINKAGE static BattleField fromString(const std::string & identifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EBoatId
|
||||||
|
{
|
||||||
|
NONE = -1,
|
||||||
|
BOAT_EVIL = 0,
|
||||||
|
BOAT_GOOD,
|
||||||
|
BOAT_NEUTRAL
|
||||||
|
};
|
||||||
|
|
||||||
|
using BoatId = Identifier<EBoatId>;
|
||||||
|
|
||||||
enum class ETerrainId {
|
enum class ETerrainId {
|
||||||
NATIVE_TERRAIN = -4,
|
NATIVE_TERRAIN = -4,
|
||||||
ANY_TERRAIN = -3,
|
ANY_TERRAIN = -3,
|
||||||
|
@ -1176,6 +1176,7 @@ void RemoveObject::applyGs(CGameState *gs)
|
|||||||
//If hero on Boat is removed, the Boat disappears
|
//If hero on Boat is removed, the Boat disappears
|
||||||
if(beatenHero->boat)
|
if(beatenHero->boat)
|
||||||
{
|
{
|
||||||
|
beatenHero->detachFrom(const_cast<CGBoat&>(*beatenHero->boat));
|
||||||
gs->map->instanceNames.erase(beatenHero->boat->instanceName);
|
gs->map->instanceNames.erase(beatenHero->boat->instanceName);
|
||||||
gs->map->objects[beatenHero->boat->id.getNum()].dellNull();
|
gs->map->objects[beatenHero->boat->id.getNum()].dellNull();
|
||||||
beatenHero->boat = nullptr;
|
beatenHero->boat = nullptr;
|
||||||
@ -1291,6 +1292,7 @@ void TryMoveHero::applyGs(CGameState *gs)
|
|||||||
|
|
||||||
gs->map->removeBlockVisTiles(boat); //hero blockvis mask will be used, we don't need to duplicate it with boat
|
gs->map->removeBlockVisTiles(boat); //hero blockvis mask will be used, we don't need to duplicate it with boat
|
||||||
h->boat = boat;
|
h->boat = boat;
|
||||||
|
h->attachTo(*boat);
|
||||||
boat->hero = h;
|
boat->hero = h;
|
||||||
}
|
}
|
||||||
else if(result == DISEMBARK) //hero leaves boat to destination tile
|
else if(result == DISEMBARK) //hero leaves boat to destination tile
|
||||||
@ -1300,6 +1302,7 @@ void TryMoveHero::applyGs(CGameState *gs)
|
|||||||
b->pos = start;
|
b->pos = start;
|
||||||
b->hero = nullptr;
|
b->hero = nullptr;
|
||||||
gs->map->addBlockVisTiles(b);
|
gs->map->addBlockVisTiles(b);
|
||||||
|
h->detachFrom(*b);
|
||||||
h->boat = nullptr;
|
h->boat = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,4 +114,12 @@ namespace NMetaclass
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace NPathfindingLayer
|
||||||
|
{
|
||||||
|
const std::string names[EPathfindingLayer::NUM_LAYERS] =
|
||||||
|
{
|
||||||
|
"land", "sail", "water", "air"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -935,18 +935,14 @@ si32 CGHeroInstance::getManaNewTurn() const
|
|||||||
// ai->putAt(this, ai->firstAvailableSlot(this));
|
// ai->putAt(this, ai->firstAvailableSlot(this));
|
||||||
// }
|
// }
|
||||||
|
|
||||||
int CGHeroInstance::getBoatType() const
|
BoatId CGHeroInstance::getBoatType() const
|
||||||
{
|
{
|
||||||
switch(type->heroClass->getAlignment())
|
switch(type->heroClass->getAlignment())
|
||||||
{
|
{
|
||||||
case EAlignment::GOOD:
|
case EAlignment::EVIL : return EBoatId::BOAT_EVIL;
|
||||||
return 1;
|
case EAlignment::GOOD : return EBoatId::BOAT_GOOD;
|
||||||
case EAlignment::EVIL:
|
case EAlignment::NEUTRAL : return EBoatId::BOAT_NEUTRAL;
|
||||||
return 0;
|
default: return EBoatId::NONE;
|
||||||
case EAlignment::NEUTRAL:
|
|
||||||
return 2;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Wrong alignment!");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,8 +1121,10 @@ int CGHeroInstance::movementPointsAfterEmbark(int MPsBefore, int basicCost, bool
|
|||||||
if(!ti->hasBonusOfType(Bonus::FREE_SHIP_BOARDING))
|
if(!ti->hasBonusOfType(Bonus::FREE_SHIP_BOARDING))
|
||||||
return 0; // take all MPs by default
|
return 0; // take all MPs by default
|
||||||
|
|
||||||
int mp1 = ti->getMaxMovePoints(disembark ? EPathfindingLayer::LAND : EPathfindingLayer::SAIL);
|
auto boatLayer = boat ? boat->layer : EPathfindingLayer::SAIL;
|
||||||
int mp2 = ti->getMaxMovePoints(disembark ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND);
|
|
||||||
|
int mp1 = ti->getMaxMovePoints(disembark ? EPathfindingLayer::LAND : boatLayer);
|
||||||
|
int mp2 = ti->getMaxMovePoints(disembark ? boatLayer : EPathfindingLayer::LAND);
|
||||||
int ret = static_cast<int>((MPsBefore - basicCost) * static_cast<double>(mp1) / mp2);
|
int ret = static_cast<int>((MPsBefore - basicCost) * static_cast<double>(mp1) / mp2);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ public:
|
|||||||
int getSightRadius() const override; //sight distance (should be used if player-owned structure)
|
int getSightRadius() const override; //sight distance (should be used if player-owned structure)
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
int getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
|
BoatId getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
|
||||||
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed
|
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1085,16 +1085,15 @@ void CGTownInstance::clearArmy() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGTownInstance::getBoatType() const
|
BoatId CGTownInstance::getBoatType() const
|
||||||
{
|
{
|
||||||
switch (town->faction->alignment)
|
switch (town->faction->alignment)
|
||||||
{
|
{
|
||||||
case EAlignment::EVIL : return 0;
|
case EAlignment::EVIL : return EBoatId::BOAT_EVIL;
|
||||||
case EAlignment::GOOD : return 1;
|
case EAlignment::GOOD : return EBoatId::BOAT_GOOD;
|
||||||
case EAlignment::NEUTRAL : return 2;
|
case EAlignment::NEUTRAL : return EBoatId::BOAT_NEUTRAL;
|
||||||
|
default: return EBoatId::NONE;
|
||||||
}
|
}
|
||||||
assert(0);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGTownInstance::getMarketEfficiency() const
|
int CGTownInstance::getMarketEfficiency() const
|
||||||
|
@ -293,7 +293,7 @@ public:
|
|||||||
bool passableFor(PlayerColor color) const override;
|
bool passableFor(PlayerColor color) const override;
|
||||||
//int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
|
//int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
|
||||||
int getSightRadius() const override; //returns sight distance
|
int getSightRadius() const override; //returns sight distance
|
||||||
int getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
|
BoatId getBoatType() const override; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
|
||||||
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed. Parameter will be cleared
|
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed. Parameter will be cleared
|
||||||
int getMarketEfficiency() const override; //=market count
|
int getMarketEfficiency() const override; //=market count
|
||||||
bool allowsTrade(EMarketMode::EMarketMode mode) const override;
|
bool allowsTrade(EMarketMode::EMarketMode mode) const override;
|
||||||
|
@ -39,6 +39,7 @@ CObjectClassesHandler::CObjectClassesHandler()
|
|||||||
SET_HANDLER_CLASS("hero", CHeroInstanceConstructor);
|
SET_HANDLER_CLASS("hero", CHeroInstanceConstructor);
|
||||||
SET_HANDLER_CLASS("town", CTownInstanceConstructor);
|
SET_HANDLER_CLASS("town", CTownInstanceConstructor);
|
||||||
SET_HANDLER_CLASS("bank", CBankInstanceConstructor);
|
SET_HANDLER_CLASS("bank", CBankInstanceConstructor);
|
||||||
|
SET_HANDLER_CLASS("boat", BoatInstanceConstructor);
|
||||||
|
|
||||||
SET_HANDLER_CLASS("static", CObstacleConstructor);
|
SET_HANDLER_CLASS("static", CObstacleConstructor);
|
||||||
SET_HANDLER_CLASS("", CObstacleConstructor);
|
SET_HANDLER_CLASS("", CObstacleConstructor);
|
||||||
@ -54,7 +55,6 @@ CObjectClassesHandler::CObjectClassesHandler()
|
|||||||
SET_HANDLER("cartographer", CCartographer);
|
SET_HANDLER("cartographer", CCartographer);
|
||||||
SET_HANDLER("artifact", CGArtifact);
|
SET_HANDLER("artifact", CGArtifact);
|
||||||
SET_HANDLER("blackMarket", CGBlackMarket);
|
SET_HANDLER("blackMarket", CGBlackMarket);
|
||||||
SET_HANDLER("boat", CGBoat);
|
|
||||||
SET_HANDLER("borderGate", CGBorderGate);
|
SET_HANDLER("borderGate", CGBorderGate);
|
||||||
SET_HANDLER("borderGuard", CGBorderGuard);
|
SET_HANDLER("borderGuard", CGBorderGuard);
|
||||||
SET_HANDLER("monster", CGCreature);
|
SET_HANDLER("monster", CGCreature);
|
||||||
|
@ -463,10 +463,10 @@ IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const
|
|||||||
return TILE_BLOCKED; //blocked
|
return TILE_BLOCKED; //blocked
|
||||||
}
|
}
|
||||||
|
|
||||||
int IBoatGenerator::getBoatType() const
|
BoatId IBoatGenerator::getBoatType() const
|
||||||
{
|
{
|
||||||
//We make good ships by default
|
//We make good ships by default
|
||||||
return 1;
|
return EBoatId::BOAT_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ public:
|
|||||||
IBoatGenerator(const CGObjectInstance *O);
|
IBoatGenerator(const CGObjectInstance *O);
|
||||||
virtual ~IBoatGenerator() = default;
|
virtual ~IBoatGenerator() = default;
|
||||||
|
|
||||||
virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
|
virtual BoatId getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
|
||||||
virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed
|
virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed
|
||||||
int3 bestLocation() const; //returns location when the boat should be placed
|
int3 bestLocation() const; //returns location when the boat should be placed
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "../CPlayerState.h"
|
#include "../CPlayerState.h"
|
||||||
#include "../spells/CSpellHandler.h"
|
#include "../spells/CSpellHandler.h"
|
||||||
#include "../spells/ISpellMechanics.h"
|
#include "../spells/ISpellMechanics.h"
|
||||||
|
#include "../mapObjects/MiscObjects.h"
|
||||||
|
|
||||||
#include "CObjectClassesHandler.h"
|
#include "CObjectClassesHandler.h"
|
||||||
|
|
||||||
@ -316,7 +317,7 @@ void CRewardableObject::grantRewardAfterLevelup(const CRewardVisitInfo & info, c
|
|||||||
smp.val = hero->movement;
|
smp.val = hero->movement;
|
||||||
|
|
||||||
if (info.reward.movePercentage >= 0) // percent from max
|
if (info.reward.movePercentage >= 0) // percent from max
|
||||||
smp.val = hero->maxMovePoints(hero->boat != nullptr) * info.reward.movePercentage / 100;
|
smp.val = hero->maxMovePoints(hero->boat && hero->boat->layer == EPathfindingLayer::SAIL) * info.reward.movePercentage / 100;
|
||||||
smp.val = std::max<si32>(0, smp.val + info.reward.movePoints);
|
smp.val = std::max<si32>(0, smp.val + info.reward.movePoints);
|
||||||
|
|
||||||
cb->setMovePoints(&smp);
|
cb->setMovePoints(&smp);
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "JsonRandom.h"
|
#include "JsonRandom.h"
|
||||||
#include "../CModHandler.h"
|
#include "../CModHandler.h"
|
||||||
#include "../IGameCallback.h"
|
#include "../IGameCallback.h"
|
||||||
|
#include "../StringConstants.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -257,6 +258,39 @@ std::vector<const CCreature *> CDwellingInstanceConstructor::getProducedCreature
|
|||||||
return creatures;
|
return creatures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BoatInstanceConstructor::initTypeData(const JsonNode & input)
|
||||||
|
{
|
||||||
|
layer = EPathfindingLayer::SAIL;
|
||||||
|
int pos = vstd::find_pos(NPathfindingLayer::names, input["layer"].String());
|
||||||
|
if(pos != -1)
|
||||||
|
layer = EPathfindingLayer(pos);
|
||||||
|
onboardAssaultAllowed = input["onboardAssaultAllowed"].Bool();
|
||||||
|
onboardVisitAllowed = input["onboardVisitAllowed"].Bool();
|
||||||
|
actualAnimation = input["actualAnimation"].String();
|
||||||
|
overlayAnimation = input["overlayAnimation"].String();
|
||||||
|
for(int i = 0; i < flagAnimations.size() && i < input["flagAnimations"].Vector().size(); ++i)
|
||||||
|
flagAnimations[i] = input["flagAnimations"].Vector()[i].String();
|
||||||
|
bonuses = JsonRandom::loadBonuses(input["bonuses"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGObjectInstance * BoatInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||||
|
{
|
||||||
|
CGBoat * boat = createTyped(tmpl);
|
||||||
|
boat->layer = layer;
|
||||||
|
boat->actualAnimation = actualAnimation;
|
||||||
|
boat->overlayAnimation = overlayAnimation;
|
||||||
|
boat->flagAnimations = flagAnimations;
|
||||||
|
for(auto & b : bonuses)
|
||||||
|
boat->addNewBonus(std::make_shared<Bonus>(b));
|
||||||
|
|
||||||
|
return boat;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoatInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool CBankInstanceConstructor::hasNameTextID() const
|
bool CBankInstanceConstructor::hasNameTextID() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -140,6 +140,37 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGBoat>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void initTypeData(const JsonNode & config) override;
|
||||||
|
|
||||||
|
std::vector<Bonus> bonuses;
|
||||||
|
EPathfindingLayer layer;
|
||||||
|
bool onboardAssaultAllowed; //if true, hero can attack units from transport
|
||||||
|
bool onboardVisitAllowed; //if true, hero can visit objects from transport
|
||||||
|
|
||||||
|
std::string actualAnimation; //for OH3 boats those have actual animations
|
||||||
|
std::string overlayAnimation; //waves animations
|
||||||
|
std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||||
|
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||||
|
|
||||||
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
|
{
|
||||||
|
h & static_cast<CDefaultObjectTypeHandler<CGBoat>&>(*this);
|
||||||
|
h & layer;
|
||||||
|
h & onboardAssaultAllowed;
|
||||||
|
h & onboardVisitAllowed;
|
||||||
|
h & bonuses;
|
||||||
|
h & actualAnimation;
|
||||||
|
h & overlayAnimation;
|
||||||
|
h & flagAnimations;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct BankConfig
|
struct BankConfig
|
||||||
{
|
{
|
||||||
ui32 value = 0; //overall value of given things
|
ui32 value = 0; //overall value of given things
|
||||||
|
@ -312,7 +312,7 @@ namespace JsonRandom
|
|||||||
std::vector<Bonus> ret;
|
std::vector<Bonus> ret;
|
||||||
for (const JsonNode & entry : value.Vector())
|
for (const JsonNode & entry : value.Vector())
|
||||||
{
|
{
|
||||||
auto bonus = JsonUtils::parseBonus(entry);
|
if(auto bonus = JsonUtils::parseBonus(entry))
|
||||||
ret.push_back(*bonus);
|
ret.push_back(*bonus);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -414,11 +414,19 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_LINKAGE CGBoat : public CGObjectInstance
|
class DLL_LINKAGE CGBoat : public CGObjectInstance, public CBonusSystemNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ui8 direction;
|
ui8 direction;
|
||||||
const CGHeroInstance *hero; //hero on board
|
const CGHeroInstance *hero; //hero on board
|
||||||
|
bool onboardAssaultAllowed; //if true, hero can attack units from transport
|
||||||
|
bool onboardVisitAllowed; //if true, hero can visit objects from transport
|
||||||
|
EPathfindingLayer::EEPathfindingLayer layer;
|
||||||
|
|
||||||
|
//animation filenames. If empty - animations won't be used
|
||||||
|
std::string actualAnimation; //for OH3 boats those have actual animations
|
||||||
|
std::string overlayAnimation; //waves animations
|
||||||
|
std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations;
|
||||||
|
|
||||||
void initObj(CRandomGenerator & rand) override;
|
void initObj(CRandomGenerator & rand) override;
|
||||||
|
|
||||||
@ -426,12 +434,20 @@ public:
|
|||||||
{
|
{
|
||||||
hero = nullptr;
|
hero = nullptr;
|
||||||
direction = 4;
|
direction = 4;
|
||||||
|
layer = EPathfindingLayer::EEPathfindingLayer::SAIL;
|
||||||
}
|
}
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & static_cast<CGObjectInstance&>(*this);
|
h & static_cast<CGObjectInstance&>(*this);
|
||||||
|
h & static_cast<CBonusSystemNode&>(*this);
|
||||||
h & direction;
|
h & direction;
|
||||||
h & hero;
|
h & hero;
|
||||||
|
h & layer;
|
||||||
|
h & onboardAssaultAllowed;
|
||||||
|
h & onboardVisitAllowed;
|
||||||
|
h & actualAnimation;
|
||||||
|
h & overlayAnimation;
|
||||||
|
h & flagAnimations;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,6 +88,7 @@ void registerTypesMapObjectTypes(Serializer &s)
|
|||||||
s.template registerType<AObjectTypeHandler, CTownInstanceConstructor>();
|
s.template registerType<AObjectTypeHandler, CTownInstanceConstructor>();
|
||||||
s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>();
|
s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>();
|
||||||
s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>();
|
s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>();
|
||||||
|
s.template registerType<AObjectTypeHandler, BoatInstanceConstructor>();
|
||||||
s.template registerType<AObjectTypeHandler, CObstacleConstructor>();
|
s.template registerType<AObjectTypeHandler, CObstacleConstructor>();
|
||||||
|
|
||||||
#define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >()
|
#define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >()
|
||||||
|
@ -185,7 +185,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
|||||||
if(obj && obj->ID == Obj::BOAT)
|
if(obj && obj->ID == Obj::BOAT)
|
||||||
{
|
{
|
||||||
const auto * b = dynamic_cast<const CGBoat *>(obj);
|
const auto * b = dynamic_cast<const CGBoat *>(obj);
|
||||||
if(b->hero)
|
if(b->hero || b->layer != EPathfindingLayer::SAIL)
|
||||||
continue; //we're looking for unoccupied boat
|
continue; //we're looking for unoccupied boat
|
||||||
|
|
||||||
double nDist = b->pos.dist2d(parameters.caster->getHeroCaster()->visitablePos());
|
double nDist = b->pos.dist2d(parameters.caster->getHeroCaster()->visitablePos());
|
||||||
@ -215,7 +215,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
|||||||
{
|
{
|
||||||
NewObject no;
|
NewObject no;
|
||||||
no.ID = Obj::BOAT;
|
no.ID = Obj::BOAT;
|
||||||
no.subID = parameters.caster->getHeroCaster()->getBoatType();
|
no.subID = parameters.caster->getHeroCaster()->getBoatType().getNum();
|
||||||
no.pos = summonPos + int3(1,0,0);
|
no.pos = summonPos + int3(1,0,0);
|
||||||
env->apply(&no);
|
env->apply(&no);
|
||||||
}
|
}
|
||||||
|
@ -2264,7 +2264,10 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
|
const int3 guardPos = gs->guardingCreaturePosition(hmpos);
|
||||||
|
|
||||||
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
|
const bool embarking = !h->boat && !t.visitableObjects.empty() && t.visitableObjects.back()->ID == Obj::BOAT;
|
||||||
const bool disembarking = h->boat && t.terType->isLand() && !t.blocked;
|
const bool disembarking = h->boat
|
||||||
|
&& t.terType->isLand()
|
||||||
|
&& (dst == h->pos
|
||||||
|
|| (h->boat->layer == EPathfindingLayer::SAIL && !t.blocked));
|
||||||
|
|
||||||
//result structure for start - movement failed, no move points used
|
//result structure for start - movement failed, no move points used
|
||||||
TryMoveHero tmh;
|
TryMoveHero tmh;
|
||||||
@ -2278,8 +2281,8 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
auto pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, h, PathfinderOptions());
|
auto pathfinderHelper = std::make_unique<CPathfinderHelper>(gs, h, PathfinderOptions());
|
||||||
auto ti = pathfinderHelper->getTurnInfo();
|
auto ti = pathfinderHelper->getTurnInfo();
|
||||||
|
|
||||||
const bool canFly = pathfinderHelper->hasBonusOfType(Bonus::FLYING_MOVEMENT);
|
const bool canFly = pathfinderHelper->hasBonusOfType(Bonus::FLYING_MOVEMENT) || (h->boat && h->boat->layer == EPathfindingLayer::AIR);
|
||||||
const bool canWalkOnSea = pathfinderHelper->hasBonusOfType(Bonus::WATER_WALKING);
|
const bool canWalkOnSea = pathfinderHelper->hasBonusOfType(Bonus::WATER_WALKING) || (h->boat && h->boat->layer == EPathfindingLayer::WATER);
|
||||||
const int cost = pathfinderHelper->getMovementCost(h->visitablePos(), hmpos, nullptr, nullptr, h->movement);
|
const int cost = pathfinderHelper->getMovementCost(h->visitablePos(), hmpos, nullptr, nullptr, h->movement);
|
||||||
|
|
||||||
//it's a rock or blocked and not visitable tile
|
//it's a rock or blocked and not visitable tile
|
||||||
@ -2288,7 +2291,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
&& complain("Cannot move hero, destination tile is blocked!"))
|
&& complain("Cannot move hero, destination tile is blocked!"))
|
||||||
|| ((!h->boat && !canWalkOnSea && !canFly && t.terType->isWater() && (t.visitableObjects.size() < 1 || (t.visitableObjects.back()->ID != Obj::BOAT && t.visitableObjects.back()->ID != Obj::HERO))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land) -> we test back cause boat may be on top of another object (#276)
|
|| ((!h->boat && !canWalkOnSea && !canFly && t.terType->isWater() && (t.visitableObjects.size() < 1 || (t.visitableObjects.back()->ID != Obj::BOAT && t.visitableObjects.back()->ID != Obj::HERO))) //hero is not on boat/water walking and dst water tile doesn't contain boat/hero (objs visitable from land) -> we test back cause boat may be on top of another object (#276)
|
||||||
&& complain("Cannot move hero, destination tile is on water!"))
|
&& complain("Cannot move hero, destination tile is on water!"))
|
||||||
|| ((h->boat && t.terType->isLand() && t.blocked)
|
|| ((h->boat && h->boat->layer == EPathfindingLayer::SAIL && t.terType->isLand() && t.blocked)
|
||||||
&& complain("Cannot disembark hero, tile is blocked!"))
|
&& complain("Cannot disembark hero, tile is blocked!"))
|
||||||
|| ((distance(h->pos, dst) >= 1.5 && !teleporting)
|
|| ((distance(h->pos, dst) >= 1.5 && !teleporting)
|
||||||
&& complain("Tiles are not neighboring!"))
|
&& complain("Tiles are not neighboring!"))
|
||||||
@ -2361,10 +2364,16 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
{
|
{
|
||||||
for (CGObjectInstance *obj : t.visitableObjects)
|
for (CGObjectInstance *obj : t.visitableObjects)
|
||||||
{
|
{
|
||||||
|
if(h->boat && !obj->blockVisit && !h->boat->onboardVisitAllowed)
|
||||||
|
return doMove(TryMoveHero::SUCCESS, this->IGNORE_GUARDS, DONT_VISIT_DEST, REMAINING_ON_TILE);
|
||||||
|
|
||||||
if (obj != h && obj->blockVisit && !obj->passableFor(h->tempOwner))
|
if (obj != h && obj->blockVisit && !obj->passableFor(h->tempOwner))
|
||||||
{
|
{
|
||||||
return doMove(TryMoveHero::BLOCKING_VISIT, this->IGNORE_GUARDS, VISIT_DEST, REMAINING_ON_TILE);
|
EVisitDest visitDest = VISIT_DEST;
|
||||||
//this-> is needed for MVS2010 to recognize scope (?)
|
if(h->boat && !h->boat->onboardVisitAllowed)
|
||||||
|
visitDest = DONT_VISIT_DEST;
|
||||||
|
|
||||||
|
return doMove(TryMoveHero::BLOCKING_VISIT, this->IGNORE_GUARDS, visitDest, REMAINING_ON_TILE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -2403,6 +2412,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//still here? it is standard movement!
|
//still here? it is standard movement!
|
||||||
{
|
{
|
||||||
tmh.movePoints = (int)h->movement >= cost
|
tmh.movePoints = (int)h->movement >= cost
|
||||||
@ -2425,6 +2435,9 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
|||||||
else if (blockingVisit())
|
else if (blockingVisit())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if(h->boat && !h->boat->onboardAssaultAllowed)
|
||||||
|
lookForGuards = IGNORE_GUARDS;
|
||||||
|
|
||||||
doMove(TryMoveHero::SUCCESS, lookForGuards, visitDest, LEAVING_TILE);
|
doMove(TryMoveHero::SUCCESS, lookForGuards, visitDest, LEAVING_TILE);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -5628,7 +5641,7 @@ bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)
|
|||||||
//create boat
|
//create boat
|
||||||
NewObject no;
|
NewObject no;
|
||||||
no.ID = Obj::BOAT;
|
no.ID = Obj::BOAT;
|
||||||
no.subID = obj->getBoatType();
|
no.subID = obj->getBoatType().getNum();
|
||||||
no.pos = tile + int3(1,0,0);
|
no.pos = tile + int3(1,0,0);
|
||||||
sendAndApply(&no);
|
sendAndApply(&no);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user