mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Implemented boat selection for town shipyards
This commit is contained in:
@@ -45,6 +45,9 @@
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
#include "../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../lib/mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../lib/mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../lib/mapObjects/CGMarket.h"
|
||||
#include "../lib/ArtifactUtils.h"
|
||||
@@ -1093,11 +1096,20 @@ CShipyardWindow::CShipyardWindow(const TResources & cost, int state, BoatId boat
|
||||
|
||||
bgWater = std::make_shared<CPicture>("TPSHIPBK", 100, 69);
|
||||
|
||||
std::string boatFilenames[3] = {"AB01_", "AB02_", "AB03_"};
|
||||
auto handler = CGI->objtypeh->getHandlerFor(Obj::BOAT, boatType);
|
||||
|
||||
Point waterCenter = Point(bgWater->pos.x+bgWater->pos.w/2, bgWater->pos.y+bgWater->pos.h/2);
|
||||
bgShip = std::make_shared<CAnimImage>(boatFilenames[boatType.getNum()], 0, 7, 120, 96, 0);
|
||||
bgShip->center(waterCenter);
|
||||
auto boatConstructor = std::dynamic_pointer_cast<const BoatInstanceConstructor>(handler);
|
||||
|
||||
assert(boatConstructor);
|
||||
|
||||
if (boatConstructor)
|
||||
{
|
||||
std::string boatFilename = boatConstructor->getBoatAnimationName();
|
||||
|
||||
Point waterCenter = Point(bgWater->pos.x+bgWater->pos.w/2, bgWater->pos.y+bgWater->pos.h/2);
|
||||
bgShip = std::make_shared<CAnimImage>(boatFilename, 0, 7, 120, 96, 0);
|
||||
bgShip->center(waterCenter);
|
||||
}
|
||||
|
||||
// Create resource icons and costs.
|
||||
std::string goldValue = std::to_string(cost[EGameResID::GOLD]);
|
||||
|
@@ -148,6 +148,7 @@
|
||||
"mageGuild" : 4,
|
||||
"warMachine" : "ballista",
|
||||
"moatAbility" : "castleMoat",
|
||||
"boat" : "boatCastle",
|
||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||
|
||||
"buildings" :
|
||||
|
@@ -153,6 +153,7 @@
|
||||
"primaryResource" : "mercury",
|
||||
"warMachine" : "ballista",
|
||||
"moatAbility" : "castleMoat",
|
||||
"boat" : "boatNecropolis",
|
||||
|
||||
"buildings" :
|
||||
{
|
||||
|
@@ -148,6 +148,7 @@
|
||||
"mageGuild" : 3,
|
||||
"warMachine" : "firstAidTent",
|
||||
"moatAbility" : "fortressMoat",
|
||||
"boat" : "boatFortress",
|
||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||
|
||||
"buildings" :
|
||||
|
@@ -153,6 +153,7 @@
|
||||
"mageGuild" : 5,
|
||||
"warMachine" : "firstAidTent",
|
||||
"moatAbility" : "necropolisMoat",
|
||||
"boat" : "boatNecropolis",
|
||||
// primaryResource not specified so town get both Wood and Ore for resource bonus
|
||||
|
||||
"buildings" :
|
||||
|
@@ -310,7 +310,7 @@
|
||||
"rmg" : {
|
||||
"value" : 500,
|
||||
"rarity" : 100
|
||||
}
|
||||
},
|
||||
"visitText" : 127,
|
||||
"spell" : {
|
||||
"level" : 1
|
||||
|
@@ -146,21 +146,21 @@
|
||||
}
|
||||
},
|
||||
"types" : {
|
||||
"evil" : // Necropolis
|
||||
"boatNecropolis" : // Necropolis
|
||||
{
|
||||
"index" : 0,
|
||||
"actualAnimation" : "AB01_.def",
|
||||
"overlayAnimation" : "ABM01_.def",
|
||||
"flagAnimations" : ["ABF01L", "ABF01G", "ABF01R", "ABF01D", "ABF01B", "ABF01P", "ABF01W", "ABF01K"]
|
||||
},
|
||||
"good" : // Castle
|
||||
"boatCastle" : // Castle
|
||||
{
|
||||
"index" : 1,
|
||||
"actualAnimation" : "AB02_.def",
|
||||
"overlayAnimation" : "ABM02_.def",
|
||||
"flagAnimations" : ["ABF02L", "ABF02G", "ABF02R", "ABF02D", "ABF02B", "ABF02P", "ABF02W", "ABF02K"]
|
||||
},
|
||||
"neutral" : { // Fortress
|
||||
"boatFortress" : { // Fortress
|
||||
"index" : 2,
|
||||
"actualAnimation" : "AB03_.def",
|
||||
"overlayAnimation" : "ABM03_.def",
|
||||
|
@@ -893,6 +893,16 @@ void CTownHandler::loadTown(CTown * town, const JsonNode & source)
|
||||
|
||||
warMachinesToLoad[town] = source["warMachine"];
|
||||
|
||||
|
||||
town->shipyardBoat = EBoatId::NONE;
|
||||
if (!source["boat"].isNull())
|
||||
{
|
||||
VLC->modh->identifiers.requestIdentifier("core:boat", source["boat"], [=](int32_t boatTypeID)
|
||||
{
|
||||
town->shipyardBoat = BoatId(boatTypeID);
|
||||
});
|
||||
}
|
||||
|
||||
town->mageLevel = static_cast<ui32>(source["mageGuild"].Float());
|
||||
|
||||
town->namesCount = 0;
|
||||
@@ -1148,6 +1158,25 @@ void CTownHandler::afterLoadFinalization()
|
||||
initializeRequirements();
|
||||
initializeOverridden();
|
||||
initializeWarMachines();
|
||||
|
||||
for(auto & faction : objects)
|
||||
{
|
||||
if (!faction->town)
|
||||
continue;
|
||||
|
||||
bool hasBoat = faction->town->shipyardBoat != EBoatId::NONE;
|
||||
bool hasShipyard = faction->town->buildings.count(BuildingID::SHIPYARD);
|
||||
|
||||
if ( hasBoat && !hasShipyard )
|
||||
logMod->warn("Town %s has boat but has no shipyard!", faction->getJsonKey());
|
||||
|
||||
if ( !hasBoat && hasShipyard )
|
||||
{
|
||||
logMod->warn("Town %s has shipyard but has no boat set!", faction->getJsonKey());
|
||||
// Mod compatibility for 1.3
|
||||
faction->town->shipyardBoat = EBoatId::CASTLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CTownHandler::initializeRequirements()
|
||||
|
@@ -281,6 +281,9 @@ public:
|
||||
GameResID primaryRes;
|
||||
ArtifactID warMachine;
|
||||
SpellID moatAbility;
|
||||
|
||||
/// boat that will be built by town shipyard, if exists
|
||||
BoatId shipyardBoat;
|
||||
// default chance for hero of specific class to appear in tavern, if field "tavern" was not set
|
||||
// resulting chance = sqrt(town.chance * heroClass.chance)
|
||||
ui32 defaultTavernChance;
|
||||
@@ -346,6 +349,7 @@ public:
|
||||
h & mageLevel;
|
||||
h & primaryRes;
|
||||
h & warMachine;
|
||||
h & shipyardBoat;
|
||||
h & clientInfo;
|
||||
h & moatAbility;
|
||||
h & defaultTavernChance;
|
||||
|
@@ -1285,9 +1285,9 @@ class BattleField : public BaseForID<BattleField, si32>
|
||||
enum class EBoatId
|
||||
{
|
||||
NONE = -1,
|
||||
BOAT_EVIL = 0,
|
||||
BOAT_GOOD,
|
||||
BOAT_NEUTRAL
|
||||
NECROPOLIS = 0,
|
||||
CASTLE,
|
||||
FORTRESS
|
||||
};
|
||||
|
||||
using BoatId = Identifier<EBoatId>;
|
||||
|
@@ -26,6 +26,15 @@ class DLL_LINKAGE TerrainType : public EntityT<TerrainId>
|
||||
TerrainId id;
|
||||
ui8 passabilityType;
|
||||
|
||||
enum PassabilityType : ui8
|
||||
{
|
||||
LAND = 1,
|
||||
WATER = 2,
|
||||
SURFACE = 4,
|
||||
SUBTERRANEAN = 8,
|
||||
ROCK = 16
|
||||
};
|
||||
|
||||
public:
|
||||
int32_t getIndex() const override { return id.getNum(); }
|
||||
int32_t getIconIndex() const override { return 0; }
|
||||
@@ -37,15 +46,6 @@ public:
|
||||
std::string getNameTextID() const override;
|
||||
std::string getNameTranslated() const override;
|
||||
|
||||
enum PassabilityType : ui8
|
||||
{
|
||||
LAND = 1,
|
||||
WATER = 2,
|
||||
SURFACE = 4,
|
||||
SUBTERRANEAN = 8,
|
||||
ROCK = 16
|
||||
};
|
||||
|
||||
std::vector<BattleField> battleFields;
|
||||
std::vector<TerrainId> prohibitTransitions;
|
||||
ColorRGBA minimapBlocked;
|
||||
|
@@ -289,11 +289,25 @@ CGObjectInstance * BoatInstanceConstructor::create(std::shared_ptr<const ObjectT
|
||||
return boat;
|
||||
}
|
||||
|
||||
std::string BoatInstanceConstructor::getBoatAnimationName() const
|
||||
{
|
||||
return actualAnimation;
|
||||
}
|
||||
|
||||
void BoatInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void BoatInstanceConstructor::afterLoadFinalization()
|
||||
{
|
||||
if (layer == EPathfindingLayer::SAIL)
|
||||
{
|
||||
if (getTemplates(TerrainId(ETerrainId::WATER)).empty())
|
||||
logMod->warn("Boat of type %s has no templates suitable for water!", getJsonKey());
|
||||
}
|
||||
}
|
||||
|
||||
void MarketInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
{
|
||||
for(auto & element : input["modes"].Vector())
|
||||
|
@@ -110,7 +110,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGBoat>
|
||||
class DLL_LINKAGE BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGBoat>
|
||||
{
|
||||
protected:
|
||||
void initTypeData(const JsonNode & config) override;
|
||||
@@ -127,6 +127,10 @@ protected:
|
||||
public:
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
void afterLoadFinalization() override;
|
||||
|
||||
/// Returns boat preview animation, for use in Shipyards
|
||||
std::string getBoatAnimationName() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@@ -953,13 +953,8 @@ si32 CGHeroInstance::getManaNewTurn() const
|
||||
|
||||
BoatId CGHeroInstance::getBoatType() const
|
||||
{
|
||||
switch (type->heroClass->getAlignment())
|
||||
{
|
||||
case EAlignment::EVIL: return EBoatId::BOAT_EVIL;
|
||||
case EAlignment::GOOD: return EBoatId::BOAT_GOOD;
|
||||
case EAlignment::NEUTRAL: return EBoatId::BOAT_NEUTRAL;
|
||||
default: return EBoatId::NONE;
|
||||
}
|
||||
// hero can only generate boat via "Summon Boat" spell which always create same boat as in Necropolis shipyard
|
||||
return EBoatId::NECROPOLIS;
|
||||
}
|
||||
|
||||
void CGHeroInstance::getOutOffsets(std::vector<int3> &offsets) const
|
||||
|
@@ -682,13 +682,7 @@ void CGTownInstance::clearArmy() const
|
||||
|
||||
BoatId CGTownInstance::getBoatType() const
|
||||
{
|
||||
switch (town->faction->alignment)
|
||||
{
|
||||
case EAlignment::EVIL : return EBoatId::BOAT_EVIL;
|
||||
case EAlignment::GOOD : return EBoatId::BOAT_GOOD;
|
||||
case EAlignment::NEUTRAL : return EBoatId::BOAT_NEUTRAL;
|
||||
default: return EBoatId::NONE;
|
||||
}
|
||||
return town->shipyardBoat;
|
||||
}
|
||||
|
||||
int CGTownInstance::getMarketEfficiency() const
|
||||
|
@@ -1961,7 +1961,8 @@ void CGShipyard::serializeJsonOptions(JsonSerializeFormat& handler)
|
||||
|
||||
BoatId CGShipyard::getBoatType() const
|
||||
{
|
||||
return EBoatId::BOAT_GOOD;
|
||||
// In H3, external shipyard will always create same boat as castle
|
||||
return EBoatId::CASTLE;
|
||||
}
|
||||
|
||||
void CCartographer::onHeroVisit( const CGHeroInstance * h ) const
|
||||
|
@@ -164,7 +164,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser)
|
||||
}
|
||||
|
||||
//assuming that object can be placed on other land terrains
|
||||
anyTerrain = allowedTerrains.size() >= 8 && !allowedTerrains.count(ETerrainId::WATER);
|
||||
anyLandTerrain = allowedTerrains.size() >= 8 && !allowedTerrains.count(ETerrainId::WATER);
|
||||
|
||||
id = Obj(boost::lexical_cast<int>(strings[5]));
|
||||
subid = boost::lexical_cast<int>(strings[6]);
|
||||
@@ -230,7 +230,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader)
|
||||
}
|
||||
|
||||
//assuming that object can be placed on other land terrains
|
||||
anyTerrain = allowedTerrains.size() >= 8 && !allowedTerrains.count(ETerrainId::WATER);
|
||||
anyLandTerrain = allowedTerrains.size() >= 8 && !allowedTerrains.count(ETerrainId::WATER);
|
||||
|
||||
id = Obj(reader.readUInt32());
|
||||
subid = reader.readUInt32();
|
||||
@@ -277,11 +277,11 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain)
|
||||
allowedTerrains.insert(TerrainId(identifier));
|
||||
});
|
||||
}
|
||||
anyTerrain = false;
|
||||
anyLandTerrain = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
anyTerrain = true;
|
||||
anyLandTerrain = true;
|
||||
}
|
||||
|
||||
auto charToTile = [&](const char & ch) -> ui8
|
||||
@@ -557,7 +557,7 @@ void ObjectTemplate::calculateVisitableOffset()
|
||||
|
||||
bool ObjectTemplate::canBePlacedAt(TerrainId terrainID) const
|
||||
{
|
||||
if (anyTerrain)
|
||||
if (anyLandTerrain)
|
||||
{
|
||||
const auto & terrain = VLC->terrainTypeHandler->getById(terrainID);
|
||||
return terrain->isLand() && terrain->isPassable();
|
||||
|
@@ -36,7 +36,7 @@ class DLL_LINKAGE ObjectTemplate
|
||||
std::set<TerrainId> allowedTerrains;
|
||||
|
||||
/// or, allow placing object on any terrain
|
||||
bool anyTerrain;
|
||||
bool anyLandTerrain;
|
||||
|
||||
void afterLoadFixup();
|
||||
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
|
||||
inline bool canBePlacedAtAnyTerrain() const
|
||||
{
|
||||
return anyTerrain;
|
||||
return anyLandTerrain;
|
||||
};
|
||||
|
||||
const std::set<TerrainId>& getAllowedTerrains() const
|
||||
@@ -159,6 +159,7 @@ public:
|
||||
{
|
||||
h & usedTiles;
|
||||
h & allowedTerrains;
|
||||
h & anyLandTerrain;
|
||||
h & animationFile;
|
||||
h & stringID;
|
||||
h & id;
|
||||
|
Reference in New Issue
Block a user