mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
Merge pull request #2209 from IvanSavenko/map_object_configuration
Support for json configuration of some map objects
This commit is contained in:
commit
2e2938303a
@ -15,7 +15,7 @@
|
||||
|
||||
#include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../../../lib/mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
|
||||
|
||||
namespace NKAI
|
||||
{
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "Nullkiller.h"
|
||||
#include "../../../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../../../lib/mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../../../lib/mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
|
||||
#include "../../../lib/mapObjects/MapObjects.h"
|
||||
#include "../../../lib/CCreatureHandler.h"
|
||||
#include "../../../lib/CPathfinder.h"
|
||||
|
@ -23,7 +23,7 @@ using namespace Goals;
|
||||
|
||||
bool BuildBoat::operator==(const BuildBoat & other) const
|
||||
{
|
||||
return shipyard->o->id == other.shipyard->o->id;
|
||||
return shipyard == other.shipyard;
|
||||
}
|
||||
//
|
||||
//TSubgoal BuildBoat::decomposeSingle() const
|
||||
@ -54,7 +54,7 @@ void BuildBoat::accept(AIGateway * ai)
|
||||
throw cannotFulfillGoalException("Can not afford boat");
|
||||
}
|
||||
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
throw cannotFulfillGoalException("Can not build boat in enemy shipyard");
|
||||
}
|
||||
@ -65,9 +65,8 @@ void BuildBoat::accept(AIGateway * ai)
|
||||
}
|
||||
|
||||
logAi->trace(
|
||||
"Building boat at shipyard %s located at %s, estimated boat position %s",
|
||||
shipyard->o->getObjectName(),
|
||||
shipyard->o->visitablePos().toString(),
|
||||
"Building boat at shipyard located at %s, estimated boat position %s",
|
||||
shipyard->getObject()->visitablePos().toString(),
|
||||
shipyard->bestLocation().toString());
|
||||
|
||||
cb->buildBoat(shipyard);
|
||||
|
@ -32,9 +32,9 @@ namespace AIPathfinding
|
||||
|
||||
Goals::TSubgoal BuildBoatAction::decompose(const CGHeroInstance * hero) const
|
||||
{
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
return Goals::sptr(Goals::CaptureObject(shipyard->o));
|
||||
return Goals::sptr(Goals::CaptureObject(targetObject()));
|
||||
}
|
||||
|
||||
return Goals::sptr(Goals::Invalid());
|
||||
@ -44,7 +44,7 @@ namespace AIPathfinding
|
||||
{
|
||||
auto hero = source->actor->hero;
|
||||
|
||||
if(cb->getPlayerRelations(hero->tempOwner, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||
if(cb->getPlayerRelations(hero->tempOwner, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
#if NKAI_TRACE_LEVEL > 1
|
||||
logAi->trace("Can not build a boat. Shipyard is enemy.");
|
||||
@ -70,7 +70,7 @@ namespace AIPathfinding
|
||||
|
||||
const CGObjectInstance * BuildBoatAction::targetObject() const
|
||||
{
|
||||
return shipyard->o;
|
||||
return dynamic_cast<const CGObjectInstance*>(shipyard);
|
||||
}
|
||||
|
||||
const ChainActor * BuildBoatAction::getActor(const ChainActor * sourceActor) const
|
||||
@ -101,7 +101,7 @@ namespace AIPathfinding
|
||||
|
||||
std::string BuildBoatAction::toString() const
|
||||
{
|
||||
return "Build Boat at " + shipyard->o->getObjectName();
|
||||
return "Build Boat at " + shipyard->getObject()->visitablePos().toString();
|
||||
}
|
||||
|
||||
bool SummonBoatAction::canAct(const AIPathNode * source) const
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include "../../lib/mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../../lib/mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../../lib/mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../../lib/mapObjectConstructors/CBankInstanceConstructor.h"
|
||||
#include "../../lib/mapObjects/CBank.h"
|
||||
#include "../../lib/mapObjects/CGDwelling.h"
|
||||
|
||||
|
@ -22,14 +22,14 @@ using namespace Goals;
|
||||
|
||||
bool BuildBoat::operator==(const BuildBoat & other) const
|
||||
{
|
||||
return shipyard->o->id == other.shipyard->o->id;
|
||||
return shipyard == other.shipyard;
|
||||
}
|
||||
|
||||
TSubgoal BuildBoat::whatToDoToAchieve()
|
||||
{
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o));
|
||||
return fh->chooseSolution(ai->ah->howToVisitObj(dynamic_cast<const CGObjectInstance*>(shipyard)));
|
||||
}
|
||||
|
||||
if(shipyard->shipyardStatus() != IShipyard::GOOD)
|
||||
@ -53,7 +53,7 @@ void BuildBoat::accept(VCAI * ai)
|
||||
throw cannotFulfillGoalException("Can not afford boat");
|
||||
}
|
||||
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
|
||||
if(cb->getPlayerRelations(ai->playerID, shipyard->getObject()->getOwner()) == PlayerRelations::ENEMIES)
|
||||
{
|
||||
throw cannotFulfillGoalException("Can not build boat in enemy shipyard");
|
||||
}
|
||||
@ -64,9 +64,8 @@ void BuildBoat::accept(VCAI * ai)
|
||||
}
|
||||
|
||||
logAi->trace(
|
||||
"Building boat at shipyard %s located at %s, estimated boat position %s",
|
||||
shipyard->o->getObjectName(),
|
||||
shipyard->o->visitablePos().toString(),
|
||||
"Building boat at shipyard located at %s, estimated boat position %s",
|
||||
shipyard->getObject()->visitablePos().toString(),
|
||||
shipyard->bestLocation().toString());
|
||||
|
||||
cb->buildBoat(shipyard);
|
||||
@ -81,5 +80,5 @@ std::string BuildBoat::name() const
|
||||
|
||||
std::string BuildBoat::completeMessage() const
|
||||
{
|
||||
return "Boat have been built at " + shipyard->o->visitablePos().toString();
|
||||
return "Boat have been built at " + shipyard->getObject()->visitablePos().toString();
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ void CCallback::sendMessage(const std::string &mess, const CGObjectInstance * cu
|
||||
void CCallback::buildBoat( const IShipyard *obj )
|
||||
{
|
||||
BuildBoat bb;
|
||||
bb.objid = obj->o->id;
|
||||
bb.objid = dynamic_cast<const CGObjectInstance*>(obj)->id;
|
||||
sendRequest(&bb);
|
||||
}
|
||||
|
||||
|
@ -906,7 +906,7 @@ void ApplyClientNetPackVisitor::visitOpenWindow(OpenWindow & pack)
|
||||
case EOpenWindowMode::SHIPYARD_WINDOW:
|
||||
{
|
||||
const IShipyard *sy = IShipyard::castFrom(cl.getObj(ObjectInstanceID(pack.id1)));
|
||||
callInterfaceIfPresent(cl, sy->o->tempOwner, &IGameEventsReceiver::showShipyardDialog, sy);
|
||||
callInterfaceIfPresent(cl, sy->getObject()->getOwner(), &IGameEventsReceiver::showShipyardDialog, sy);
|
||||
}
|
||||
break;
|
||||
case EOpenWindowMode::THIEVES_GUILD:
|
||||
|
@ -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]);
|
||||
|
@ -66,9 +66,14 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/logging/CLogger.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/AObjectTypeHandler.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CBankInstanceConstructor.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CObjectClassesHandler.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CommonConstructors.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CRewardableConstructor.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/DwellingInstanceConstructor.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/HillFortInstanceConstructor.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/ShipyardInstanceConstructor.cpp
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/ShrineInstanceConstructor.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/mapObjects/CArmedInstance.cpp
|
||||
${MAIN_LIB_DIR}/mapObjects/CBank.cpp
|
||||
@ -369,11 +374,17 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/logging/CLogger.h
|
||||
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/AObjectTypeHandler.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CBankInstanceConstructor.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CDefaultObjectTypeHandler.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CObjectClassesHandler.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CommonConstructors.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/CRewardableConstructor.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/DwellingInstanceConstructor.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/HillFortInstanceConstructor.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/IObjectInfo.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/RandomMapInfo.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/ShipyardInstanceConstructor.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/ShrineInstanceConstructor.h
|
||||
${MAIN_LIB_DIR}/mapObjectConstructors/SObjectSounds.h
|
||||
|
||||
${MAIN_LIB_DIR}/mapObjects/CArmedInstance.h
|
||||
|
@ -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,6 +310,10 @@
|
||||
"rmg" : {
|
||||
"value" : 500,
|
||||
"rarity" : 100
|
||||
},
|
||||
"visitText" : 127,
|
||||
"spell" : {
|
||||
"level" : 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -330,6 +334,10 @@
|
||||
"rmg" : {
|
||||
"value" : 2000,
|
||||
"rarity" : 100
|
||||
},
|
||||
"visitText" : 128,
|
||||
"spell" : {
|
||||
"level" : 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -350,6 +358,10 @@
|
||||
"rmg" : {
|
||||
"value" : 3000,
|
||||
"rarity" : 100
|
||||
},
|
||||
"visitText" : 129,
|
||||
"spell" : {
|
||||
"level" : 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -476,7 +488,8 @@
|
||||
"index" : 0,
|
||||
"aiValue" : 1000,
|
||||
"rmg" : {
|
||||
}
|
||||
},
|
||||
"boat" : "boatCastle"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -640,19 +653,6 @@
|
||||
},
|
||||
"randomDwelling" : { "index" :216, "handler": "randomDwelling", "types" : { "object" : { "index" : 0} } },
|
||||
|
||||
"randomResource" : {
|
||||
"index" :76,
|
||||
"handler": "randomResource",
|
||||
"types" : {
|
||||
"object" : {
|
||||
"index" : 0,
|
||||
"templates" : {
|
||||
"normal" : { "animation" : "AVTrndm0", "visitableFrom" : [ "+++", "+-+", "+++" ], "mask" : [ "VV", "VA"] }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"randomArtifact" : {
|
||||
"index" :65,
|
||||
"handler": "randomArtifact",
|
||||
@ -830,7 +830,7 @@
|
||||
/// Classes without dedicated object
|
||||
"hillFort" : {
|
||||
"index" :35,
|
||||
"handler": "generic",
|
||||
"handler": "hillFort",
|
||||
"base" : {
|
||||
"sounds" : {
|
||||
"ambient" : ["LOOPSWAR"],
|
||||
@ -845,7 +845,14 @@
|
||||
"zoneLimit" : 1,
|
||||
"value" : 7000,
|
||||
"rarity" : 20
|
||||
}
|
||||
},
|
||||
"upgradeCostFactor" : [
|
||||
0, // level 1
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100 // level 5+
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -861,7 +868,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"marketOfTime" : { // Unused/not implemented H3 object present on some maps RoE maps
|
||||
"marketOfTime" : { // Unused/not implemented H3 object present on some RoE maps
|
||||
"index" :50,
|
||||
"handler": "generic"
|
||||
},
|
||||
|
@ -53,7 +53,7 @@
|
||||
"randomResource":
|
||||
{
|
||||
"index" :76,
|
||||
"handler": "resource",
|
||||
"handler": "randomResource",
|
||||
"base" : {
|
||||
"base" : {
|
||||
"visitableFrom" : [ "+++", "+-+", "+++" ],
|
||||
@ -69,9 +69,10 @@
|
||||
},
|
||||
"templates" :
|
||||
{
|
||||
"res" :
|
||||
{
|
||||
"animation" : "AVTrndm0.def"
|
||||
"normal" : {
|
||||
"animation" : "AVTrndm0",
|
||||
"visitableFrom" : [ "+++", "+-+", "+++" ],
|
||||
"mask" : [ "VV", "VA"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,21 +147,19 @@
|
||||
}
|
||||
},
|
||||
"types" : {
|
||||
"evil" : // Necropolis
|
||||
{
|
||||
"boatNecropolis" : {
|
||||
"index" : 0,
|
||||
"actualAnimation" : "AB01_.def",
|
||||
"overlayAnimation" : "ABM01_.def",
|
||||
"flagAnimations" : ["ABF01L", "ABF01G", "ABF01R", "ABF01D", "ABF01B", "ABF01P", "ABF01W", "ABF01K"]
|
||||
},
|
||||
"good" : // Castle
|
||||
{
|
||||
"boatCastle" : {
|
||||
"index" : 1,
|
||||
"actualAnimation" : "AB02_.def",
|
||||
"overlayAnimation" : "ABM02_.def",
|
||||
"flagAnimations" : ["ABF02L", "ABF02G", "ABF02R", "ABF02D", "ABF02B", "ABF02P", "ABF02W", "ABF02K"]
|
||||
},
|
||||
"neutral" : { // Fortress
|
||||
"boatFortress" : {
|
||||
"index" : 2,
|
||||
"actualAnimation" : "AB03_.def",
|
||||
"overlayAnimation" : "ABM03_.def",
|
||||
|
@ -124,6 +124,10 @@
|
||||
"type" : "string",
|
||||
"description" : "Identifier of war machine produced by blacksmith in town"
|
||||
},
|
||||
"boat" : {
|
||||
"type" : "string",
|
||||
"description" : "Identifier of boat type that is produced by shipyard in town, if any"
|
||||
},
|
||||
"horde" : {
|
||||
"type" : "array",
|
||||
"maxItems" : 2,
|
||||
|
@ -15,6 +15,7 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class SpellID;
|
||||
enum class ESpellSchool: int8_t;
|
||||
|
||||
namespace spells
|
||||
{
|
||||
@ -43,6 +44,7 @@ public:
|
||||
virtual bool isSpecial() const = 0;
|
||||
virtual bool isMagical() const = 0; //Should this spell considered as magical effect or as ability (like dendroid's bind)
|
||||
|
||||
virtual bool hasSchool(ESpellSchool school) const = 0;
|
||||
virtual void forEachSchool(const SchoolCallback & cb) const = 0;
|
||||
virtual const std::string & getCastSound() const = 0;
|
||||
virtual int32_t getCost(const int32_t skillLevel) const = 0;
|
||||
|
@ -621,7 +621,7 @@ std::pair<Obj,int> CGameState::pickObject (CGObjectInstance *obj)
|
||||
auto dwellingIDs = VLC->objtypeh->knownSubObjects(primaryID);
|
||||
for (si32 entry : dwellingIDs)
|
||||
{
|
||||
const auto * handler = dynamic_cast<const CDwellingInstanceConstructor *>(VLC->objtypeh->getHandlerFor(primaryID, entry).get());
|
||||
const auto * handler = dynamic_cast<const DwellingInstanceConstructor *>(VLC->objtypeh->getHandlerFor(primaryID, entry).get());
|
||||
|
||||
if (handler->producesCreature(VLC->creh->objects[cid]))
|
||||
result = std::make_pair(primaryID, entry);
|
||||
@ -2018,54 +2018,28 @@ UpgradeInfo CGameState::fillUpgradeInfo(const CStackInstance &stack) const
|
||||
UpgradeInfo ret;
|
||||
const CCreature *base = stack.type;
|
||||
|
||||
const CGHeroInstance * h = stack.armyObj->ID == Obj::HERO ? dynamic_cast<const CGHeroInstance *>(stack.armyObj) : nullptr;
|
||||
const CGTownInstance *t = nullptr;
|
||||
|
||||
if(stack.armyObj->ID == Obj::TOWN)
|
||||
t = dynamic_cast<const CGTownInstance *>(stack.armyObj);
|
||||
else if(h)
|
||||
{ //hero specialty
|
||||
TConstBonusListPtr lista = h->getBonuses(Selector::typeSubtype(BonusType::SPECIAL_UPGRADE, base->getId()));
|
||||
for(const auto & it : *lista)
|
||||
{
|
||||
auto nid = CreatureID(it->additionalInfo[0]);
|
||||
if (nid != base->getId()) //in very specific case the upgrade is available by default (?)
|
||||
{
|
||||
ret.newID.push_back(nid);
|
||||
ret.cost.push_back(nid.toCreature()->getFullRecruitCost() - base->getFullRecruitCost());
|
||||
}
|
||||
}
|
||||
t = h->visitedTown;
|
||||
}
|
||||
if(t)
|
||||
if (stack.armyObj->ID == Obj::HERO)
|
||||
{
|
||||
for(const CGTownInstance::TCreaturesSet::value_type & dwelling : t->creatures)
|
||||
auto hero = dynamic_cast<const CGHeroInstance *>(stack.armyObj);
|
||||
hero->fillUpgradeInfo(ret, stack);
|
||||
|
||||
if (hero->visitedTown)
|
||||
{
|
||||
if (vstd::contains(dwelling.second, base->getId())) //Dwelling with our creature
|
||||
{
|
||||
for(const auto & upgrID : dwelling.second)
|
||||
{
|
||||
if(vstd::contains(base->upgrades, upgrID)) //possible upgrade
|
||||
{
|
||||
ret.newID.push_back(upgrID);
|
||||
ret.cost.push_back(upgrID.toCreature()->getFullRecruitCost() - base->getFullRecruitCost());
|
||||
}
|
||||
}
|
||||
}
|
||||
hero->visitedTown->fillUpgradeInfo(ret, stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto object = vstd::frontOrNull(getVisitableObjs(hero->visitablePos()));
|
||||
auto upgradeSource = dynamic_cast<const ICreatureUpgrader*>(object);
|
||||
if (object != hero && upgradeSource != nullptr)
|
||||
upgradeSource->fillUpgradeInfo(ret, stack);
|
||||
}
|
||||
}
|
||||
|
||||
//hero is visiting Hill Fort
|
||||
if(h && map->getTile(h->visitablePos()).visitableObjects.front()->ID == Obj::HILL_FORT)
|
||||
if (stack.armyObj->ID == Obj::TOWN)
|
||||
{
|
||||
static const int costModifiers[] = {0, 25, 50, 75, 100}; //we get cheaper upgrades depending on level
|
||||
const int costModifier = costModifiers[std::min<int>(std::max((int)base->getLevel() - 1, 0), std::size(costModifiers) - 1)];
|
||||
|
||||
for(const auto & nid : base->upgrades)
|
||||
{
|
||||
ret.newID.push_back(nid);
|
||||
ret.cost.push_back((nid.toCreature()->getFullRecruitCost() - base->getFullRecruitCost()) * costModifier / 100);
|
||||
}
|
||||
auto town = dynamic_cast<const CGTownInstance *>(stack.armyObj);
|
||||
town->fillUpgradeInfo(ret, stack);
|
||||
}
|
||||
|
||||
if(!ret.newID.empty())
|
||||
|
@ -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>;
|
||||
|
@ -170,16 +170,19 @@ void CPrivilegedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact *>
|
||||
out.push_back(VLC->arth->objects[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR)]);
|
||||
}
|
||||
|
||||
void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, ui16 level)
|
||||
void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level)
|
||||
{
|
||||
for (ui32 i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?)
|
||||
{
|
||||
|
||||
const spells::Spell * spell = SpellID(i).toSpell();
|
||||
if(isAllowed(0, spell->getIndex()) && spell->getLevel() == level)
|
||||
{
|
||||
out.push_back(spell->getId());
|
||||
}
|
||||
|
||||
if (!isAllowed(0, spell->getIndex()))
|
||||
continue;
|
||||
|
||||
if (level.has_value() && spell->getLevel() != level)
|
||||
continue;
|
||||
|
||||
out.push_back(spell->getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ public:
|
||||
|
||||
//gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant
|
||||
void pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand) const;
|
||||
void getAllowedSpells(std::vector<SpellID> &out, ui16 level);
|
||||
void getAllowedSpells(std::vector<SpellID> &out, std::optional<ui16> level = std::nullopt);
|
||||
|
||||
template<typename Saver>
|
||||
void saveCommonState(Saver &out) const; //stores GS and VLC
|
||||
|
@ -243,21 +243,36 @@ namespace JsonRandom
|
||||
if (value.getType() == JsonNode::JsonType::DATA_STRING)
|
||||
return SpellID(VLC->modh->identifiers.getIdentifier("spell", value).value());
|
||||
|
||||
vstd::erase_if(spells, [=](const SpellID & spell)
|
||||
if (!value["level"].isNull())
|
||||
{
|
||||
return VLC->spellh->getById(spell)->getLevel() != si32(value["level"].Float());
|
||||
});
|
||||
int32_t spellLevel = value["level"].Float();
|
||||
|
||||
vstd::erase_if(spells, [=](const SpellID & spell)
|
||||
{
|
||||
return VLC->spellh->getById(spell)->getLevel() != spellLevel;
|
||||
});
|
||||
}
|
||||
|
||||
if (!value["school"].isNull())
|
||||
{
|
||||
int32_t schoolID = VLC->modh->identifiers.getIdentifier("spellSchool", value["school"]).value();
|
||||
|
||||
vstd::erase_if(spells, [=](const SpellID & spell)
|
||||
{
|
||||
return !VLC->spellh->getById(spell)->hasSchool(ESpellSchool(schoolID));
|
||||
});
|
||||
}
|
||||
|
||||
if (spells.empty())
|
||||
{
|
||||
logMod->warn("Failed to select suitable random spell!");
|
||||
return SpellID::NONE;
|
||||
}
|
||||
return SpellID(*RandomGeneratorUtil::nextItem(spells, rng));
|
||||
}
|
||||
|
||||
std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const std::vector<SpellID> & spells)
|
||||
{
|
||||
// possible extensions: (taken from spell json config)
|
||||
// "type": "adventure",//"adventure", "combat", "ability"
|
||||
// "school": {"air":true, "earth":true, "fire":true, "water":true},
|
||||
// "level": 1,
|
||||
|
||||
std::vector<SpellID> ret;
|
||||
for (const JsonNode & entry : value.Vector())
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "StdInc.h"
|
||||
#include "AObjectTypeHandler.h"
|
||||
|
||||
#include "IObjectInfo.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../mapObjects/CGObjectInstance.h"
|
||||
@ -221,5 +222,9 @@ void AObjectTypeHandler::afterLoadFinalization()
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<IObjectInfo> AObjectTypeHandler::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -107,7 +107,7 @@ public:
|
||||
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0;
|
||||
|
||||
/// Returns object configuration, if available. Otherwise returns NULL
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const = 0;
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
248
lib/mapObjectConstructors/CBankInstanceConstructor.cpp
Normal file
248
lib/mapObjectConstructors/CBankInstanceConstructor.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* CBankInstanceConstructor.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "CBankInstanceConstructor.h"
|
||||
|
||||
#include "../JsonRandom.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../IGameCallback.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
bool CBankInstanceConstructor::hasNameTextID() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBankInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
{
|
||||
if (input.Struct().count("name") == 0)
|
||||
logMod->warn("Bank %s missing name!", getJsonKey());
|
||||
|
||||
VLC->generaltexth->registerString(input.meta, getNameTextID(), input["name"].String());
|
||||
|
||||
levels = input["levels"].Vector();
|
||||
bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
|
||||
}
|
||||
|
||||
BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const
|
||||
{
|
||||
BankConfig bc;
|
||||
|
||||
bc.chance = static_cast<ui32>(level["chance"].Float());
|
||||
|
||||
bc.guards = JsonRandom::loadCreatures(level["guards"], rng);
|
||||
bc.upgradeChance = static_cast<ui32>(level["upgrade_chance"].Float());
|
||||
bc.combatValue = static_cast<ui32>(level["combat_value"].Float());
|
||||
|
||||
std::vector<SpellID> spells;
|
||||
IObjectInterface::cb->getAllowedSpells(spells);
|
||||
|
||||
bc.resources = ResourceSet(level["reward"]["resources"]);
|
||||
bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng);
|
||||
bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng);
|
||||
bc.spells = JsonRandom::loadSpells(level["reward"]["spells"], rng, spells);
|
||||
|
||||
bc.value = static_cast<ui32>(level["value"].Float());
|
||||
|
||||
return bc;
|
||||
}
|
||||
|
||||
void CBankInstanceConstructor::randomizeObject(CBank * bank, CRandomGenerator & rng) const
|
||||
{
|
||||
bank->resetDuration = bankResetDuration;
|
||||
|
||||
si32 totalChance = 0;
|
||||
for(const auto & node : levels)
|
||||
totalChance += static_cast<si32>(node["chance"].Float());
|
||||
|
||||
assert(totalChance != 0);
|
||||
|
||||
si32 selectedChance = rng.nextInt(totalChance - 1);
|
||||
|
||||
int cumulativeChance = 0;
|
||||
for(const auto & node : levels)
|
||||
{
|
||||
cumulativeChance += static_cast<int>(node["chance"].Float());
|
||||
if(selectedChance < cumulativeChance)
|
||||
{
|
||||
bank->setConfig(generateConfig(node, rng));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBankInfo::CBankInfo(const JsonVector & Config) :
|
||||
config(Config)
|
||||
{
|
||||
assert(!Config.empty());
|
||||
}
|
||||
|
||||
static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature * crea, si32 amount)
|
||||
{
|
||||
army.totalStrength += crea->getFightValue() * amount;
|
||||
|
||||
bool walker = true;
|
||||
if(crea->hasBonusOfType(BonusType::SHOOTER))
|
||||
{
|
||||
army.shootersStrength += crea->getFightValue() * amount;
|
||||
walker = false;
|
||||
}
|
||||
if(crea->hasBonusOfType(BonusType::FLYING))
|
||||
{
|
||||
army.flyersStrength += crea->getFightValue() * amount;
|
||||
walker = false;
|
||||
}
|
||||
if(walker)
|
||||
army.walkersStrength += crea->getFightValue() * amount;
|
||||
}
|
||||
|
||||
IObjectInfo::CArmyStructure CBankInfo::minGuards() const
|
||||
{
|
||||
std::vector<IObjectInfo::CArmyStructure> armies;
|
||||
for(auto configEntry : config)
|
||||
{
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
for(auto & stack : stacks)
|
||||
{
|
||||
assert(!stack.allowedCreatures.empty());
|
||||
auto weakest = boost::range::min_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
|
||||
{
|
||||
return a->getFightValue() < b->getFightValue();
|
||||
});
|
||||
addStackToArmy(army, *weakest, stack.minAmount);
|
||||
}
|
||||
armies.push_back(army);
|
||||
}
|
||||
return *boost::range::min_element(armies);
|
||||
}
|
||||
|
||||
IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
|
||||
{
|
||||
std::vector<IObjectInfo::CArmyStructure> armies;
|
||||
for(auto configEntry : config)
|
||||
{
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
for(auto & stack : stacks)
|
||||
{
|
||||
assert(!stack.allowedCreatures.empty());
|
||||
auto strongest = boost::range::max_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
|
||||
{
|
||||
return a->getFightValue() < b->getFightValue();
|
||||
});
|
||||
addStackToArmy(army, *strongest, stack.maxAmount);
|
||||
}
|
||||
armies.push_back(army);
|
||||
}
|
||||
return *boost::range::max_element(armies);
|
||||
}
|
||||
|
||||
TPossibleGuards CBankInfo::getPossibleGuards() const
|
||||
{
|
||||
TPossibleGuards out;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["guards"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
|
||||
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
army.totalStrength += stack.allowedCreatures.front()->getAIValue() * (stack.minAmount + stack.maxAmount) / 2;
|
||||
//TODO: add fields for flyers, walkers etc...
|
||||
}
|
||||
|
||||
ui8 chance = static_cast<ui8>(configEntry["chance"].Float());
|
||||
out.push_back(std::make_pair(chance, army));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<PossibleReward<TResources>> CBankInfo::getPossibleResourcesReward() const
|
||||
{
|
||||
std::vector<PossibleReward<TResources>> result;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & resourcesInfo = configEntry["reward"]["resources"];
|
||||
|
||||
if(!resourcesInfo.isNull())
|
||||
{
|
||||
result.emplace_back(configEntry["chance"].Integer(), TResources(resourcesInfo));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> CBankInfo::getPossibleCreaturesReward() const
|
||||
{
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> aproximateReward;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["reward"]["creatures"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
|
||||
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
const auto * creature = stack.allowedCreatures.front();
|
||||
|
||||
aproximateReward.emplace_back(configEntry["chance"].Integer(), CStackBasicDescriptor(creature, (stack.minAmount + stack.maxAmount) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
return aproximateReward;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesResources() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["resources"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesArtifacts() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["artifacts"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesCreatures() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["creatures"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesSpells() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["spells"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return std::unique_ptr<IObjectInfo>(new CBankInfo(levels));
|
||||
}
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
104
lib/mapObjectConstructors/CBankInstanceConstructor.h
Normal file
104
lib/mapObjectConstructors/CBankInstanceConstructor.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* CBankInstanceConstructor.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultObjectTypeHandler.h"
|
||||
#include "IObjectInfo.h"
|
||||
|
||||
#include "../CCreatureSet.h"
|
||||
#include "../ResourceSet.h"
|
||||
#include "../mapObjects/CBank.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BankConfig
|
||||
{
|
||||
ui32 value = 0; //overall value of given things
|
||||
ui32 chance = 0; //chance for this level being chosen
|
||||
ui32 upgradeChance = 0; //chance for creatures to be in upgraded versions
|
||||
ui32 combatValue = 0; //how hard are guards of this level
|
||||
std::vector<CStackBasicDescriptor> guards; //creature ID, amount
|
||||
ResourceSet resources; //resources given in case of victory
|
||||
std::vector<CStackBasicDescriptor> creatures; //creatures granted in case of victory (creature ID, amount)
|
||||
std::vector<ArtifactID> artifacts; //artifacts given in case of victory
|
||||
std::vector<SpellID> spells; // granted spell(s), for Pyramid
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & chance;
|
||||
h & upgradeChance;
|
||||
h & guards;
|
||||
h & combatValue;
|
||||
h & resources;
|
||||
h & creatures;
|
||||
h & artifacts;
|
||||
h & value;
|
||||
h & spells;
|
||||
}
|
||||
};
|
||||
|
||||
using TPossibleGuards = std::vector<std::pair<ui8, IObjectInfo::CArmyStructure>>;
|
||||
|
||||
template <typename T>
|
||||
struct DLL_LINKAGE PossibleReward
|
||||
{
|
||||
int chance;
|
||||
T data;
|
||||
|
||||
PossibleReward(int chance, const T & data) : chance(chance), data(data) {}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CBankInfo : public IObjectInfo
|
||||
{
|
||||
const JsonVector & config;
|
||||
public:
|
||||
CBankInfo(const JsonVector & Config);
|
||||
|
||||
TPossibleGuards getPossibleGuards() const;
|
||||
std::vector<PossibleReward<TResources>> getPossibleResourcesReward() const;
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> getPossibleCreaturesReward() const;
|
||||
|
||||
// These functions should try to evaluate minimal possible/max possible guards to give provide information on possible thread to AI
|
||||
CArmyStructure minGuards() const override;
|
||||
CArmyStructure maxGuards() const override;
|
||||
|
||||
bool givesResources() const override;
|
||||
bool givesArtifacts() const override;
|
||||
bool givesCreatures() const override;
|
||||
bool givesSpells() const override;
|
||||
};
|
||||
|
||||
class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
|
||||
{
|
||||
BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const;
|
||||
|
||||
JsonVector levels;
|
||||
protected:
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
// all banks of this type will be reset N days after clearing,
|
||||
si32 bankResetDuration = 0;
|
||||
|
||||
void randomizeObject(CBank * object, CRandomGenerator & rng) const override;
|
||||
|
||||
bool hasNameTextID() const override;
|
||||
|
||||
std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & levels;
|
||||
h & bankResetDuration;
|
||||
h & static_cast<CDefaultObjectTypeHandler<CBank>&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
53
lib/mapObjectConstructors/CDefaultObjectTypeHandler.h
Normal file
53
lib/mapObjectConstructors/CDefaultObjectTypeHandler.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* CDefaultObjectTypeHandler.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "AObjectTypeHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
/// Class that is used as base for multiple object constructors
|
||||
template<class ObjectType>
|
||||
class CDefaultObjectTypeHandler : public AObjectTypeHandler
|
||||
{
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const final
|
||||
{
|
||||
ObjectType * castedObject = dynamic_cast<ObjectType*>(object);
|
||||
|
||||
if(castedObject == nullptr)
|
||||
throw std::runtime_error("Unexpected object type!");
|
||||
|
||||
randomizeObject(castedObject, rng);
|
||||
}
|
||||
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const final
|
||||
{
|
||||
ObjectType * result = createObject();
|
||||
|
||||
preInitObject(result);
|
||||
|
||||
if(tmpl)
|
||||
result->appearance = tmpl;
|
||||
|
||||
initializeObject(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void initializeObject(ObjectType * object) const {}
|
||||
virtual void randomizeObject(ObjectType * object, CRandomGenerator & rng) const {}
|
||||
virtual ObjectType * createObject() const
|
||||
{
|
||||
return new ObjectType();
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -21,11 +21,21 @@
|
||||
#include "../JsonNode.h"
|
||||
#include "../CSoundBase.h"
|
||||
|
||||
#include "../mapObjectConstructors/CBankInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/CRewardableConstructor.h"
|
||||
#include "../mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../mapObjects/CQuest.h"
|
||||
#include "../mapObjectConstructors/DwellingInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/HillFortInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/ShipyardInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/ShrineInstanceConstructor.h"
|
||||
#include "../mapObjects/CGPandoraBox.h"
|
||||
#include "../mapObjects/CQuest.h"
|
||||
#include "../mapObjects/ObjectTemplate.h"
|
||||
#include "../mapObjects/CGMarket.h"
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../mapObjects/CGTownInstance.h"
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -37,12 +47,15 @@ CObjectClassesHandler::CObjectClassesHandler()
|
||||
// list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code
|
||||
//Note: should be in sync with registerTypesMapObjectTypes function
|
||||
SET_HANDLER_CLASS("configurable", CRewardableConstructor);
|
||||
SET_HANDLER_CLASS("dwelling", CDwellingInstanceConstructor);
|
||||
SET_HANDLER_CLASS("dwelling", DwellingInstanceConstructor);
|
||||
SET_HANDLER_CLASS("hero", CHeroInstanceConstructor);
|
||||
SET_HANDLER_CLASS("town", CTownInstanceConstructor);
|
||||
SET_HANDLER_CLASS("bank", CBankInstanceConstructor);
|
||||
SET_HANDLER_CLASS("boat", BoatInstanceConstructor);
|
||||
SET_HANDLER_CLASS("market", MarketInstanceConstructor);
|
||||
SET_HANDLER_CLASS("shrine", ShrineInstanceConstructor);
|
||||
SET_HANDLER_CLASS("hillFort", HillFortInstanceConstructor);
|
||||
SET_HANDLER_CLASS("shipyard", ShipyardInstanceConstructor);
|
||||
|
||||
SET_HANDLER_CLASS("static", CObstacleConstructor);
|
||||
SET_HANDLER_CLASS("", CObstacleConstructor);
|
||||
@ -76,8 +89,6 @@ CObjectClassesHandler::CObjectClassesHandler()
|
||||
SET_HANDLER("resource", CGResource);
|
||||
SET_HANDLER("scholar", CGScholar);
|
||||
SET_HANDLER("seerHut", CGSeerHut);
|
||||
SET_HANDLER("shipyard", CGShipyard);
|
||||
SET_HANDLER("shrine", CGShrine);
|
||||
SET_HANDLER("sign", CGSignBottle);
|
||||
SET_HANDLER("siren", CGSirens);
|
||||
SET_HANDLER("monolith", CGMonolith);
|
||||
|
@ -10,19 +10,23 @@
|
||||
#include "StdInc.h"
|
||||
#include "CommonConstructors.h"
|
||||
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../CHeroHandler.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "../IGameCallback.h"
|
||||
#include "../JsonRandom.h"
|
||||
#include "../StringConstants.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../mapObjects/CBank.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../mapObjects/CGMarket.h"
|
||||
#include "../mapObjects/CGTownInstance.h"
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
#include "../mapObjects/ObjectTemplate.h"
|
||||
|
||||
#include "../mapping/CMapDefines.h"
|
||||
#include "JsonRandom.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -69,15 +73,13 @@ bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, std
|
||||
return filters.count(templ->stringID) != 0 && filters.at(templ->stringID).test(buildTest);
|
||||
}
|
||||
|
||||
CGObjectInstance * CTownInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
void CTownInstanceConstructor::initializeObject(CGTownInstance * obj) const
|
||||
{
|
||||
CGTownInstance * obj = createTyped(tmpl);
|
||||
obj->town = faction->town;
|
||||
obj->tempOwner = PlayerColor::NEUTRAL;
|
||||
return obj;
|
||||
}
|
||||
|
||||
void CTownInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||
void CTownInstanceConstructor::randomizeObject(CGTownInstance * object, CRandomGenerator & rng) const
|
||||
{
|
||||
auto templ = getOverride(CGObjectInstance::cb->getTile(object->pos)->terType->getId(), object);
|
||||
if(templ)
|
||||
@ -121,144 +123,16 @@ bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, std
|
||||
return false;
|
||||
}
|
||||
|
||||
CGObjectInstance * CHeroInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
void CHeroInstanceConstructor::initializeObject(CGHeroInstance * obj) const
|
||||
{
|
||||
CGHeroInstance * obj = createTyped(tmpl);
|
||||
obj->type = nullptr; //FIXME: set to valid value. somehow.
|
||||
return obj;
|
||||
}
|
||||
|
||||
void CHeroInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||
void CHeroInstanceConstructor::randomizeObject(CGHeroInstance * object, CRandomGenerator & rng) const
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool CDwellingInstanceConstructor::hasNameTextID() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDwellingInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
{
|
||||
if (input.Struct().count("name") == 0)
|
||||
logMod->warn("Dwelling %s missing name!", getJsonKey());
|
||||
|
||||
VLC->generaltexth->registerString( input.meta, getNameTextID(), input["name"].String());
|
||||
|
||||
const JsonVector & levels = input["creatures"].Vector();
|
||||
const auto totalLevels = levels.size();
|
||||
|
||||
availableCreatures.resize(totalLevels);
|
||||
for(auto currentLevel = 0; currentLevel < totalLevels; currentLevel++)
|
||||
{
|
||||
const JsonVector & creaturesOnLevel = levels[currentLevel].Vector();
|
||||
const auto creaturesNumber = creaturesOnLevel.size();
|
||||
availableCreatures[currentLevel].resize(creaturesNumber);
|
||||
|
||||
for(auto currentCreature = 0; currentCreature < creaturesNumber; currentCreature++)
|
||||
{
|
||||
VLC->modh->identifiers.requestIdentifier("creature", creaturesOnLevel[currentCreature], [=] (si32 index)
|
||||
{
|
||||
availableCreatures[currentLevel][currentCreature] = VLC->creh->objects[index];
|
||||
});
|
||||
}
|
||||
assert(!availableCreatures[currentLevel].empty());
|
||||
}
|
||||
guards = input["guards"];
|
||||
}
|
||||
|
||||
bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance * obj, std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CGObjectInstance * CDwellingInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
CGDwelling * obj = createTyped(tmpl);
|
||||
|
||||
obj->creatures.resize(availableCreatures.size());
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
for(const CCreature * cre : entry)
|
||||
obj->creatures.back().second.push_back(cre->getId());
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
void CDwellingInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator &rng) const
|
||||
{
|
||||
auto * dwelling = dynamic_cast<CGDwelling *>(object);
|
||||
|
||||
dwelling->creatures.clear();
|
||||
dwelling->creatures.reserve(availableCreatures.size());
|
||||
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
dwelling->creatures.resize(dwelling->creatures.size() + 1);
|
||||
for(const CCreature * cre : entry)
|
||||
dwelling->creatures.back().second.push_back(cre->getId());
|
||||
}
|
||||
|
||||
bool guarded = false; //TODO: serialize for sanity
|
||||
|
||||
if(guards.getType() == JsonNode::JsonType::DATA_BOOL) //simple switch
|
||||
{
|
||||
if(guards.Bool())
|
||||
{
|
||||
guarded = true;
|
||||
}
|
||||
}
|
||||
else if(guards.getType() == JsonNode::JsonType::DATA_VECTOR) //custom guards (eg. Elemental Conflux)
|
||||
{
|
||||
for(auto & stack : JsonRandom::loadCreatures(guards, rng))
|
||||
{
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->getId(), stack.count));
|
||||
}
|
||||
}
|
||||
else //default condition - creatures are of level 5 or higher
|
||||
{
|
||||
for(auto creatureEntry : availableCreatures)
|
||||
{
|
||||
if(creatureEntry.at(0)->getLevel() >= 5)
|
||||
{
|
||||
guarded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(guarded)
|
||||
{
|
||||
for(auto creatureEntry : availableCreatures)
|
||||
{
|
||||
const CCreature * crea = creatureEntry.at(0);
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(crea->getId(), crea->getGrowth() * 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CDwellingInstanceConstructor::producesCreature(const CCreature * crea) const
|
||||
{
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
for(const CCreature * cre : entry)
|
||||
if(crea == cre)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const CCreature *> CDwellingInstanceConstructor::getProducedCreatures() const
|
||||
{
|
||||
std::vector<const CCreature *> creatures; //no idea why it's 2D, to be honest
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
for(const CCreature * cre : entry)
|
||||
creatures.push_back(cre);
|
||||
}
|
||||
return creatures;
|
||||
}
|
||||
|
||||
void BoatInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
{
|
||||
layer = EPathfindingLayer::SAIL;
|
||||
@ -274,9 +148,8 @@ void BoatInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
bonuses = JsonRandom::loadBonuses(input["bonuses"]);
|
||||
}
|
||||
|
||||
CGObjectInstance * BoatInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
void BoatInstanceConstructor::initializeObject(CGBoat * boat) const
|
||||
{
|
||||
CGBoat * boat = createTyped(tmpl);
|
||||
boat->layer = layer;
|
||||
boat->actualAnimation = actualAnimation;
|
||||
boat->overlayAnimation = overlayAnimation;
|
||||
@ -285,13 +158,20 @@ CGObjectInstance * BoatInstanceConstructor::create(std::shared_ptr<const ObjectT
|
||||
boat->onboardVisitAllowed = onboardVisitAllowed;
|
||||
for(auto & b : bonuses)
|
||||
boat->addNewBonus(std::make_shared<Bonus>(b));
|
||||
|
||||
return boat;
|
||||
}
|
||||
|
||||
void BoatInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||
std::string BoatInstanceConstructor::getBoatAnimationName() const
|
||||
{
|
||||
return actualAnimation;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -309,31 +189,25 @@ void MarketInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
speech = input["speech"].String();
|
||||
}
|
||||
|
||||
CGObjectInstance * MarketInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
CGMarket * MarketInstanceConstructor::createObject() const
|
||||
{
|
||||
CGMarket * market = nullptr;
|
||||
if(marketModes.size() == 1)
|
||||
{
|
||||
switch(*marketModes.begin())
|
||||
{
|
||||
case EMarketMode::ARTIFACT_RESOURCE:
|
||||
case EMarketMode::RESOURCE_ARTIFACT:
|
||||
market = new CGBlackMarket;
|
||||
break;
|
||||
|
||||
return new CGBlackMarket;
|
||||
|
||||
case EMarketMode::RESOURCE_SKILL:
|
||||
market = new CGUniversity;
|
||||
break;
|
||||
return new CGUniversity;
|
||||
}
|
||||
}
|
||||
|
||||
if(!market)
|
||||
market = new CGMarket;
|
||||
|
||||
preInitObject(market);
|
||||
return new CGMarket;
|
||||
}
|
||||
|
||||
if(tmpl)
|
||||
market->appearance = tmpl;
|
||||
void MarketInstanceConstructor::initializeObject(CGMarket * market) const
|
||||
{
|
||||
market->marketModes = marketModes;
|
||||
market->marketEfficiency = marketEfficiency;
|
||||
|
||||
@ -343,11 +217,9 @@ CGObjectInstance * MarketInstanceConstructor::create(std::shared_ptr<const Objec
|
||||
|
||||
if (!speech.empty())
|
||||
market->speech = VLC->generaltexth->translate(speech);
|
||||
|
||||
return market;
|
||||
}
|
||||
|
||||
void MarketInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||
void MarketInstanceConstructor::randomizeObject(CGMarket * object, CRandomGenerator & rng) const
|
||||
{
|
||||
if(auto * university = dynamic_cast<CGUniversity *>(object))
|
||||
{
|
||||
@ -356,241 +228,4 @@ void MarketInstanceConstructor::configureObject(CGObjectInstance * object, CRand
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CBankInstanceConstructor::hasNameTextID() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CBankInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
{
|
||||
if (input.Struct().count("name") == 0)
|
||||
logMod->warn("Bank %s missing name!", getJsonKey());
|
||||
|
||||
VLC->generaltexth->registerString(input.meta, getNameTextID(), input["name"].String());
|
||||
|
||||
levels = input["levels"].Vector();
|
||||
bankResetDuration = static_cast<si32>(input["resetDuration"].Float());
|
||||
}
|
||||
|
||||
CGObjectInstance *CBankInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return createTyped(tmpl);
|
||||
}
|
||||
|
||||
BankConfig CBankInstanceConstructor::generateConfig(const JsonNode & level, CRandomGenerator & rng) const
|
||||
{
|
||||
BankConfig bc;
|
||||
|
||||
bc.chance = static_cast<ui32>(level["chance"].Float());
|
||||
|
||||
bc.guards = JsonRandom::loadCreatures(level["guards"], rng);
|
||||
bc.upgradeChance = static_cast<ui32>(level["upgrade_chance"].Float());
|
||||
bc.combatValue = static_cast<ui32>(level["combat_value"].Float());
|
||||
|
||||
std::vector<SpellID> spells;
|
||||
for (size_t i=0; i<6; i++)
|
||||
IObjectInterface::cb->getAllowedSpells(spells, static_cast<ui16>(i));
|
||||
|
||||
bc.resources = ResourceSet(level["reward"]["resources"]);
|
||||
bc.creatures = JsonRandom::loadCreatures(level["reward"]["creatures"], rng);
|
||||
bc.artifacts = JsonRandom::loadArtifacts(level["reward"]["artifacts"], rng);
|
||||
bc.spells = JsonRandom::loadSpells(level["reward"]["spells"], rng, spells);
|
||||
|
||||
bc.value = static_cast<ui32>(level["value"].Float());
|
||||
|
||||
return bc;
|
||||
}
|
||||
|
||||
void CBankInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const
|
||||
{
|
||||
auto * bank = dynamic_cast<CBank *>(object);
|
||||
|
||||
bank->resetDuration = bankResetDuration;
|
||||
|
||||
si32 totalChance = 0;
|
||||
for(const auto & node : levels)
|
||||
totalChance += static_cast<si32>(node["chance"].Float());
|
||||
|
||||
assert(totalChance != 0);
|
||||
|
||||
si32 selectedChance = rng.nextInt(totalChance - 1);
|
||||
|
||||
int cumulativeChance = 0;
|
||||
for(const auto & node : levels)
|
||||
{
|
||||
cumulativeChance += static_cast<int>(node["chance"].Float());
|
||||
if(selectedChance < cumulativeChance)
|
||||
{
|
||||
bank->setConfig(generateConfig(node, rng));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CBankInfo::CBankInfo(const JsonVector & Config) :
|
||||
config(Config)
|
||||
{
|
||||
assert(!Config.empty());
|
||||
}
|
||||
|
||||
static void addStackToArmy(IObjectInfo::CArmyStructure & army, const CCreature * crea, si32 amount)
|
||||
{
|
||||
army.totalStrength += crea->getFightValue() * amount;
|
||||
|
||||
bool walker = true;
|
||||
if(crea->hasBonusOfType(BonusType::SHOOTER))
|
||||
{
|
||||
army.shootersStrength += crea->getFightValue() * amount;
|
||||
walker = false;
|
||||
}
|
||||
if(crea->hasBonusOfType(BonusType::FLYING))
|
||||
{
|
||||
army.flyersStrength += crea->getFightValue() * amount;
|
||||
walker = false;
|
||||
}
|
||||
if(walker)
|
||||
army.walkersStrength += crea->getFightValue() * amount;
|
||||
}
|
||||
|
||||
IObjectInfo::CArmyStructure CBankInfo::minGuards() const
|
||||
{
|
||||
std::vector<IObjectInfo::CArmyStructure> armies;
|
||||
for(auto configEntry : config)
|
||||
{
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
for(auto & stack : stacks)
|
||||
{
|
||||
assert(!stack.allowedCreatures.empty());
|
||||
auto weakest = boost::range::min_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
|
||||
{
|
||||
return a->getFightValue() < b->getFightValue();
|
||||
});
|
||||
addStackToArmy(army, *weakest, stack.minAmount);
|
||||
}
|
||||
armies.push_back(army);
|
||||
}
|
||||
return *boost::range::min_element(armies);
|
||||
}
|
||||
|
||||
IObjectInfo::CArmyStructure CBankInfo::maxGuards() const
|
||||
{
|
||||
std::vector<IObjectInfo::CArmyStructure> armies;
|
||||
for(auto configEntry : config)
|
||||
{
|
||||
auto stacks = JsonRandom::evaluateCreatures(configEntry["guards"]);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
for(auto & stack : stacks)
|
||||
{
|
||||
assert(!stack.allowedCreatures.empty());
|
||||
auto strongest = boost::range::max_element(stack.allowedCreatures, [](const CCreature * a, const CCreature * b)
|
||||
{
|
||||
return a->getFightValue() < b->getFightValue();
|
||||
});
|
||||
addStackToArmy(army, *strongest, stack.maxAmount);
|
||||
}
|
||||
armies.push_back(army);
|
||||
}
|
||||
return *boost::range::max_element(armies);
|
||||
}
|
||||
|
||||
TPossibleGuards CBankInfo::getPossibleGuards() const
|
||||
{
|
||||
TPossibleGuards out;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["guards"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
|
||||
IObjectInfo::CArmyStructure army;
|
||||
|
||||
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
army.totalStrength += stack.allowedCreatures.front()->getAIValue() * (stack.minAmount + stack.maxAmount) / 2;
|
||||
//TODO: add fields for flyers, walkers etc...
|
||||
}
|
||||
|
||||
ui8 chance = static_cast<ui8>(configEntry["chance"].Float());
|
||||
out.push_back(std::make_pair(chance, army));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<PossibleReward<TResources>> CBankInfo::getPossibleResourcesReward() const
|
||||
{
|
||||
std::vector<PossibleReward<TResources>> result;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & resourcesInfo = configEntry["reward"]["resources"];
|
||||
|
||||
if(!resourcesInfo.isNull())
|
||||
{
|
||||
result.emplace_back(configEntry["chance"].Integer(), TResources(resourcesInfo));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> CBankInfo::getPossibleCreaturesReward() const
|
||||
{
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> aproximateReward;
|
||||
|
||||
for(const JsonNode & configEntry : config)
|
||||
{
|
||||
const JsonNode & guardsInfo = configEntry["reward"]["creatures"];
|
||||
auto stacks = JsonRandom::evaluateCreatures(guardsInfo);
|
||||
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
const auto * creature = stack.allowedCreatures.front();
|
||||
|
||||
aproximateReward.emplace_back(configEntry["chance"].Integer(), CStackBasicDescriptor(creature, (stack.minAmount + stack.maxAmount) / 2));
|
||||
}
|
||||
}
|
||||
|
||||
return aproximateReward;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesResources() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["resources"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesArtifacts() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["artifacts"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesCreatures() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["creatures"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBankInfo::givesSpells() const
|
||||
{
|
||||
for(const JsonNode & node : config)
|
||||
if(!node["reward"]["spells"].isNull())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return std::unique_ptr<IObjectInfo>(new CBankInfo(levels));
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -9,63 +9,24 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "AObjectTypeHandler.h"
|
||||
|
||||
#include "../mapObjects/CGMarket.h"
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../mapObjects/CGTownInstance.h"
|
||||
#include "../mapObjects/CBank.h"
|
||||
#include "CDefaultObjectTypeHandler.h"
|
||||
#include "../LogicalExpression.h"
|
||||
#include "IObjectInfo.h"
|
||||
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGArtifact;
|
||||
class CGObjectInstance;
|
||||
class CGTownInstance;
|
||||
class CGHeroInstance;
|
||||
class CGDwelling;
|
||||
class CGMarket;
|
||||
class CHeroClass;
|
||||
class CBank;
|
||||
class CGBoat;
|
||||
class CFaction;
|
||||
class CStackBasicDescriptor;
|
||||
|
||||
/// Class that is used for objects that do not have dedicated handler
|
||||
template<class ObjectType>
|
||||
class CDefaultObjectTypeHandler : public AObjectTypeHandler
|
||||
{
|
||||
protected:
|
||||
ObjectType * createTyped(std::shared_ptr<const ObjectTemplate> tmpl /* = nullptr */) const
|
||||
{
|
||||
auto obj = new ObjectType();
|
||||
preInitObject(obj);
|
||||
|
||||
//Set custom template or leave null
|
||||
if (tmpl)
|
||||
{
|
||||
obj->appearance = tmpl;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
public:
|
||||
CDefaultObjectTypeHandler() {}
|
||||
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override
|
||||
{
|
||||
return createTyped(tmpl);
|
||||
}
|
||||
|
||||
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
class CObstacleConstructor : public CDefaultObjectTypeHandler<CGObjectInstance>
|
||||
{
|
||||
public:
|
||||
@ -83,8 +44,8 @@ public:
|
||||
CFaction * faction = nullptr;
|
||||
std::map<std::string, LogicalExpression<BuildingID>> filters;
|
||||
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
void initializeObject(CGTownInstance * object) const override;
|
||||
void randomizeObject(CGTownInstance * object, CRandomGenerator & rng) const override;
|
||||
void afterLoadFinalization() override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
@ -107,8 +68,8 @@ public:
|
||||
CHeroClass * heroClass = nullptr;
|
||||
std::map<std::string, LogicalExpression<HeroTypeID>> filters;
|
||||
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
void initializeObject(CGHeroInstance * object) const override;
|
||||
void randomizeObject(CGHeroInstance * object, CRandomGenerator & rng) const override;
|
||||
void afterLoadFinalization() override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
@ -120,34 +81,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling>
|
||||
{
|
||||
std::vector<std::vector<const CCreature *>> availableCreatures;
|
||||
|
||||
JsonNode guards;
|
||||
|
||||
protected:
|
||||
bool objectFilter(const CGObjectInstance * obj, std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
bool hasNameTextID() const override;
|
||||
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
|
||||
bool producesCreature(const CCreature * crea) const;
|
||||
std::vector<const CCreature *> getProducedCreatures() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & availableCreatures;
|
||||
h & guards;
|
||||
h & static_cast<CDefaultObjectTypeHandler<CGDwelling>&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGBoat>
|
||||
class DLL_LINKAGE BoatInstanceConstructor : public CDefaultObjectTypeHandler<CGBoat>
|
||||
{
|
||||
protected:
|
||||
void initTypeData(const JsonNode & config) override;
|
||||
@ -162,8 +96,11 @@ protected:
|
||||
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;
|
||||
void initializeObject(CGBoat * object) 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)
|
||||
{
|
||||
@ -178,90 +115,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct BankConfig
|
||||
{
|
||||
ui32 value = 0; //overall value of given things
|
||||
ui32 chance = 0; //chance for this level being chosen
|
||||
ui32 upgradeChance = 0; //chance for creatures to be in upgraded versions
|
||||
ui32 combatValue = 0; //how hard are guards of this level
|
||||
std::vector<CStackBasicDescriptor> guards; //creature ID, amount
|
||||
ResourceSet resources; //resources given in case of victory
|
||||
std::vector<CStackBasicDescriptor> creatures; //creatures granted in case of victory (creature ID, amount)
|
||||
std::vector<ArtifactID> artifacts; //artifacts given in case of victory
|
||||
std::vector<SpellID> spells; // granted spell(s), for Pyramid
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & chance;
|
||||
h & upgradeChance;
|
||||
h & guards;
|
||||
h & combatValue;
|
||||
h & resources;
|
||||
h & creatures;
|
||||
h & artifacts;
|
||||
h & value;
|
||||
h & spells;
|
||||
}
|
||||
};
|
||||
|
||||
using TPossibleGuards = std::vector<std::pair<ui8, IObjectInfo::CArmyStructure>>;
|
||||
|
||||
template <typename T>
|
||||
struct DLL_LINKAGE PossibleReward
|
||||
{
|
||||
int chance;
|
||||
T data;
|
||||
|
||||
PossibleReward(int chance, const T & data) : chance(chance), data(data) {}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CBankInfo : public IObjectInfo
|
||||
{
|
||||
const JsonVector & config;
|
||||
public:
|
||||
CBankInfo(const JsonVector & Config);
|
||||
|
||||
TPossibleGuards getPossibleGuards() const;
|
||||
std::vector<PossibleReward<TResources>> getPossibleResourcesReward() const;
|
||||
std::vector<PossibleReward<CStackBasicDescriptor>> getPossibleCreaturesReward() const;
|
||||
|
||||
// These functions should try to evaluate minimal possible/max possible guards to give provide information on possible thread to AI
|
||||
CArmyStructure minGuards() const override;
|
||||
CArmyStructure maxGuards() const override;
|
||||
|
||||
bool givesResources() const override;
|
||||
bool givesArtifacts() const override;
|
||||
bool givesCreatures() const override;
|
||||
bool givesSpells() const override;
|
||||
};
|
||||
|
||||
class CBankInstanceConstructor : public CDefaultObjectTypeHandler<CBank>
|
||||
{
|
||||
BankConfig generateConfig(const JsonNode & conf, CRandomGenerator & rng) const;
|
||||
|
||||
JsonVector levels;
|
||||
protected:
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
// all banks of this type will be reset N days after clearing,
|
||||
si32 bankResetDuration = 0;
|
||||
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
|
||||
bool hasNameTextID() const override;
|
||||
|
||||
std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & levels;
|
||||
h & bankResetDuration;
|
||||
h & static_cast<CDefaultObjectTypeHandler<CBank>&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
class MarketInstanceConstructor : public CDefaultObjectTypeHandler<CGMarket>
|
||||
{
|
||||
protected:
|
||||
@ -274,8 +127,9 @@ protected:
|
||||
std::string title, speech;
|
||||
|
||||
public:
|
||||
CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override;
|
||||
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
|
||||
CGMarket * createObject() const override;
|
||||
void initializeObject(CGMarket * object) const override;
|
||||
void randomizeObject(CGMarket * object, CRandomGenerator & rng) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
146
lib/mapObjectConstructors/DwellingInstanceConstructor.cpp
Normal file
146
lib/mapObjectConstructors/DwellingInstanceConstructor.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* DwellingInstanceConstructor.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "DwellingInstanceConstructor.h"
|
||||
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "../JsonRandom.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../mapObjects/CGDwelling.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
bool DwellingInstanceConstructor::hasNameTextID() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void DwellingInstanceConstructor::initTypeData(const JsonNode & input)
|
||||
{
|
||||
if (input.Struct().count("name") == 0)
|
||||
logMod->warn("Dwelling %s missing name!", getJsonKey());
|
||||
|
||||
VLC->generaltexth->registerString( input.meta, getNameTextID(), input["name"].String());
|
||||
|
||||
const JsonVector & levels = input["creatures"].Vector();
|
||||
const auto totalLevels = levels.size();
|
||||
|
||||
availableCreatures.resize(totalLevels);
|
||||
for(auto currentLevel = 0; currentLevel < totalLevels; currentLevel++)
|
||||
{
|
||||
const JsonVector & creaturesOnLevel = levels[currentLevel].Vector();
|
||||
const auto creaturesNumber = creaturesOnLevel.size();
|
||||
availableCreatures[currentLevel].resize(creaturesNumber);
|
||||
|
||||
for(auto currentCreature = 0; currentCreature < creaturesNumber; currentCreature++)
|
||||
{
|
||||
VLC->modh->identifiers.requestIdentifier("creature", creaturesOnLevel[currentCreature], [=] (si32 index)
|
||||
{
|
||||
availableCreatures[currentLevel][currentCreature] = VLC->creh->objects[index];
|
||||
});
|
||||
}
|
||||
assert(!availableCreatures[currentLevel].empty());
|
||||
}
|
||||
guards = input["guards"];
|
||||
}
|
||||
|
||||
bool DwellingInstanceConstructor::objectFilter(const CGObjectInstance * obj, std::shared_ptr<const ObjectTemplate> tmpl) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DwellingInstanceConstructor::initializeObject(CGDwelling * obj) const
|
||||
{
|
||||
obj->creatures.resize(availableCreatures.size());
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
for(const CCreature * cre : entry)
|
||||
obj->creatures.back().second.push_back(cre->getId());
|
||||
}
|
||||
}
|
||||
|
||||
void DwellingInstanceConstructor::randomizeObject(CGDwelling * object, CRandomGenerator &rng) const
|
||||
{
|
||||
auto * dwelling = dynamic_cast<CGDwelling *>(object);
|
||||
|
||||
dwelling->creatures.clear();
|
||||
dwelling->creatures.reserve(availableCreatures.size());
|
||||
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
dwelling->creatures.resize(dwelling->creatures.size() + 1);
|
||||
for(const CCreature * cre : entry)
|
||||
dwelling->creatures.back().second.push_back(cre->getId());
|
||||
}
|
||||
|
||||
bool guarded = false; //TODO: serialize for sanity
|
||||
|
||||
if(guards.getType() == JsonNode::JsonType::DATA_BOOL) //simple switch
|
||||
{
|
||||
if(guards.Bool())
|
||||
{
|
||||
guarded = true;
|
||||
}
|
||||
}
|
||||
else if(guards.getType() == JsonNode::JsonType::DATA_VECTOR) //custom guards (eg. Elemental Conflux)
|
||||
{
|
||||
for(auto & stack : JsonRandom::loadCreatures(guards, rng))
|
||||
{
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(stack.type->getId(), stack.count));
|
||||
}
|
||||
}
|
||||
else //default condition - creatures are of level 5 or higher
|
||||
{
|
||||
for(auto creatureEntry : availableCreatures)
|
||||
{
|
||||
if(creatureEntry.at(0)->getLevel() >= 5)
|
||||
{
|
||||
guarded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(guarded)
|
||||
{
|
||||
for(auto creatureEntry : availableCreatures)
|
||||
{
|
||||
const CCreature * crea = creatureEntry.at(0);
|
||||
dwelling->putStack(SlotID(dwelling->stacksCount()), new CStackInstance(crea->getId(), crea->getGrowth() * 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DwellingInstanceConstructor::producesCreature(const CCreature * crea) const
|
||||
{
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
for(const CCreature * cre : entry)
|
||||
if(crea == cre)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<const CCreature *> DwellingInstanceConstructor::getProducedCreatures() const
|
||||
{
|
||||
std::vector<const CCreature *> creatures; //no idea why it's 2D, to be honest
|
||||
for(const auto & entry : availableCreatures)
|
||||
{
|
||||
for(const CCreature * cre : entry)
|
||||
creatures.push_back(cre);
|
||||
}
|
||||
return creatures;
|
||||
}
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
45
lib/mapObjectConstructors/DwellingInstanceConstructor.h
Normal file
45
lib/mapObjectConstructors/DwellingInstanceConstructor.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* DwellingInstanceConstructor.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultObjectTypeHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGDwelling;
|
||||
|
||||
class DwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling>
|
||||
{
|
||||
std::vector<std::vector<const CCreature *>> availableCreatures;
|
||||
|
||||
JsonNode guards;
|
||||
|
||||
protected:
|
||||
bool objectFilter(const CGObjectInstance * obj, std::shared_ptr<const ObjectTemplate> tmpl) const override;
|
||||
void initTypeData(const JsonNode & input) override;
|
||||
|
||||
public:
|
||||
bool hasNameTextID() const override;
|
||||
|
||||
void initializeObject(CGDwelling * object) const override;
|
||||
void randomizeObject(CGDwelling * object, CRandomGenerator & rng) const override;
|
||||
|
||||
bool producesCreature(const CCreature * crea) const;
|
||||
std::vector<const CCreature *> getProducedCreatures() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & availableCreatures;
|
||||
h & guards;
|
||||
h & static_cast<CDefaultObjectTypeHandler<CGDwelling>&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
27
lib/mapObjectConstructors/HillFortInstanceConstructor.cpp
Normal file
27
lib/mapObjectConstructors/HillFortInstanceConstructor.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* HillFortInstanceConstructor.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "HillFortInstanceConstructor.h"
|
||||
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void HillFortInstanceConstructor::initTypeData(const JsonNode & config)
|
||||
{
|
||||
parameters = config;
|
||||
}
|
||||
|
||||
void HillFortInstanceConstructor::initializeObject(HillFort * fort) const
|
||||
{
|
||||
fort->upgradeCostPercentage = parameters["upgradeCostFactor"].convertTo<std::vector<int>>();
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
34
lib/mapObjectConstructors/HillFortInstanceConstructor.h
Normal file
34
lib/mapObjectConstructors/HillFortInstanceConstructor.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* HillFortInstanceConstructor.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultObjectTypeHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class HillFort;
|
||||
|
||||
class HillFortInstanceConstructor final : public CDefaultObjectTypeHandler<HillFort>
|
||||
{
|
||||
JsonNode parameters;
|
||||
|
||||
protected:
|
||||
void initTypeData(const JsonNode & config) override;
|
||||
void initializeObject(HillFort * object) const override;
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<AObjectTypeHandler&>(*this);
|
||||
h & parameters;
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
28
lib/mapObjectConstructors/ShipyardInstanceConstructor.cpp
Normal file
28
lib/mapObjectConstructors/ShipyardInstanceConstructor.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* ShipyardInstanceConstructor.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "ShipyardInstanceConstructor.h"
|
||||
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
#include "../CModHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void ShipyardInstanceConstructor::initTypeData(const JsonNode & config)
|
||||
{
|
||||
parameters = config;
|
||||
}
|
||||
|
||||
void ShipyardInstanceConstructor::initializeObject(CGShipyard * shipyard) const
|
||||
{
|
||||
shipyard->createdBoat = BoatId(*VLC->modh->identifiers.getIdentifier("core:boat", parameters["boat"]));
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
34
lib/mapObjectConstructors/ShipyardInstanceConstructor.h
Normal file
34
lib/mapObjectConstructors/ShipyardInstanceConstructor.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* ShipyardInstanceConstructor.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultObjectTypeHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGShipyard;
|
||||
|
||||
class ShipyardInstanceConstructor final : public CDefaultObjectTypeHandler<CGShipyard>
|
||||
{
|
||||
JsonNode parameters;
|
||||
|
||||
protected:
|
||||
void initTypeData(const JsonNode & config) override;
|
||||
void initializeObject(CGShipyard * object) const override;
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<AObjectTypeHandler&>(*this);
|
||||
h & parameters;
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
42
lib/mapObjectConstructors/ShrineInstanceConstructor.cpp
Normal file
42
lib/mapObjectConstructors/ShrineInstanceConstructor.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* ShrineInstanceConstructor.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "ShrineInstanceConstructor.h"
|
||||
|
||||
#include "../mapObjects/MiscObjects.h"
|
||||
#include "../JsonRandom.h"
|
||||
#include "../IGameCallback.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
void ShrineInstanceConstructor::initTypeData(const JsonNode & config)
|
||||
{
|
||||
parameters = config;
|
||||
}
|
||||
|
||||
void ShrineInstanceConstructor::randomizeObject(CGShrine * shrine, CRandomGenerator & rng) const
|
||||
{
|
||||
auto visitTextParameter = parameters["visitText"];
|
||||
|
||||
if (visitTextParameter.isNumber())
|
||||
shrine->visitText.addTxt(MetaString::ADVOB_TXT, static_cast<ui32>(visitTextParameter.Float()));
|
||||
else
|
||||
shrine->visitText << visitTextParameter.String();
|
||||
|
||||
if(shrine->spell == SpellID::NONE) // shrine has no predefined spell
|
||||
{
|
||||
std::vector<SpellID> possibilities;
|
||||
shrine->cb->getAllowedSpells(possibilities);
|
||||
|
||||
shrine->spell =JsonRandom::loadSpell(parameters["spell"], rng, possibilities);
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
34
lib/mapObjectConstructors/ShrineInstanceConstructor.h
Normal file
34
lib/mapObjectConstructors/ShrineInstanceConstructor.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* ShrineInstanceConstructor.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "CDefaultObjectTypeHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class CGShrine;
|
||||
|
||||
class ShrineInstanceConstructor final : public CDefaultObjectTypeHandler<CGShrine>
|
||||
{
|
||||
JsonNode parameters;
|
||||
|
||||
protected:
|
||||
void initTypeData(const JsonNode & config) override;
|
||||
void randomizeObject(CGShrine * object, CRandomGenerator & rng) const override;
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<AObjectTypeHandler&>(*this);
|
||||
h & parameters;
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@ -18,7 +18,7 @@
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../CSoundBase.h"
|
||||
#include "../mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../mapObjectConstructors/CBankInstanceConstructor.h"
|
||||
#include "../IGameCallback.h"
|
||||
#include "../CGameState.h"
|
||||
|
||||
|
@ -225,7 +225,6 @@ int CGHeroInstance::maxMovePointsCached(bool onLand, const TurnInfo * ti) const
|
||||
}
|
||||
|
||||
CGHeroInstance::CGHeroInstance():
|
||||
IBoatGenerator(this),
|
||||
tacticFormationEnabled(false),
|
||||
inTownGarrison(false),
|
||||
moveDir(4),
|
||||
@ -453,7 +452,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
|
||||
//Create a new boat for hero
|
||||
NewObject no;
|
||||
no.ID = Obj::BOAT;
|
||||
no.subID = BoatId(EBoatId::BOAT_NEUTRAL);
|
||||
no.subID = BoatId(EBoatId::CASTLE);
|
||||
no.pos = CGBoat::translatePos(boatPos);
|
||||
|
||||
cb->sendAndApply(&no);
|
||||
@ -954,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
|
||||
@ -973,6 +967,11 @@ void CGHeroInstance::getOutOffsets(std::vector<int3> &offsets) const
|
||||
};
|
||||
}
|
||||
|
||||
const IObjectInterface * CGHeroInstance::getObject() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
int32_t CGHeroInstance::getSpellCost(const spells::Spell * sp) const
|
||||
{
|
||||
return sp->getCost(getSpellSchoolLevel(sp));
|
||||
@ -1715,4 +1714,18 @@ bool CGHeroInstance::isMissionCritical() const
|
||||
return false;
|
||||
}
|
||||
|
||||
void CGHeroInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const
|
||||
{
|
||||
TConstBonusListPtr lista = getBonuses(Selector::typeSubtype(BonusType::SPECIAL_UPGRADE, stack.type->getId()));
|
||||
for(const auto & it : *lista)
|
||||
{
|
||||
auto nid = CreatureID(it->additionalInfo[0]);
|
||||
if (nid != stack.type->getId()) //in very specific case the upgrade is available by default (?)
|
||||
{
|
||||
info.newID.push_back(nid);
|
||||
info.cost.push_back(nid.toCreature()->getFullRecruitCost() - stack.type->getFullRecruitCost());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public spells::Caster, public AFactionMember
|
||||
class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public spells::Caster, public AFactionMember, public ICreatureUpgrader
|
||||
{
|
||||
// We serialize heroes into JSON for crossover
|
||||
friend class CCampaignState;
|
||||
@ -133,6 +133,7 @@ public:
|
||||
|
||||
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
|
||||
const IObjectInterface * getObject() const override;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -230,6 +231,8 @@ public:
|
||||
void recreateSecondarySkillsBonuses();
|
||||
void updateSkillBonus(const SecondarySkill & which, int val);
|
||||
|
||||
void fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const override;
|
||||
|
||||
bool hasVisions(const CGObjectInstance * target, const int subtype) const;
|
||||
/// If this hero perishes, the scenario is failed
|
||||
bool isMissionCritical() const;
|
||||
|
@ -254,11 +254,6 @@ void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
switch(ID)
|
||||
{
|
||||
case Obj::HILL_FORT:
|
||||
{
|
||||
openWindow(EOpenWindowMode::HILL_FORT_WINDOW,id.getNum(),h->id.getNum());
|
||||
}
|
||||
break;
|
||||
case Obj::SANCTUARY:
|
||||
{
|
||||
//You enter the sanctuary and immediately feel as if a great weight has been lifted off your shoulders. You feel safe here.
|
||||
|
@ -224,8 +224,6 @@ bool CGTownInstance::hasCapitol() const
|
||||
}
|
||||
|
||||
CGTownInstance::CGTownInstance():
|
||||
IShipyard(this),
|
||||
IMarket(),
|
||||
town(nullptr),
|
||||
builded(0),
|
||||
destroyed(0),
|
||||
@ -590,6 +588,19 @@ void CGTownInstance::getOutOffsets( std::vector<int3> &offsets ) const
|
||||
offsets = {int3(-1,2,0), int3(-3,2,0)};
|
||||
}
|
||||
|
||||
CGTownInstance::EGeneratorState CGTownInstance::shipyardStatus() const
|
||||
{
|
||||
if (!hasBuilt(BuildingID::SHIPYARD))
|
||||
return EGeneratorState::UNKNOWN;
|
||||
|
||||
return IShipyard::shipyardStatus();
|
||||
}
|
||||
|
||||
const IObjectInterface * CGTownInstance::getObject() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void CGTownInstance::mergeGarrisonOnSiege() const
|
||||
{
|
||||
auto getWeakestStackSlot = [&](ui64 powerLimit)
|
||||
@ -671,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
|
||||
@ -1242,5 +1247,22 @@ int GrowthInfo::totalGrowth() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CGTownInstance::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const
|
||||
{
|
||||
for(const CGTownInstance::TCreaturesSet::value_type & dwelling : creatures)
|
||||
{
|
||||
if (vstd::contains(dwelling.second, stack.type->getId())) //Dwelling with our creature
|
||||
{
|
||||
for(const auto & upgrID : dwelling.second)
|
||||
{
|
||||
if(vstd::contains(stack.type->upgrades, upgrID)) //possible upgrade
|
||||
{
|
||||
info.newID.push_back(upgrID);
|
||||
info.cost.push_back(upgrID.toCreature()->getFullRecruitCost() - stack.type->getFullRecruitCost());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -42,10 +42,12 @@ struct DLL_LINKAGE GrowthInfo
|
||||
int totalGrowth() const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider
|
||||
class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket, public INativeTerrainProvider, public ICreatureUpgrader
|
||||
{
|
||||
std::string name; // name of town
|
||||
public:
|
||||
using CGDwelling::getPosition;
|
||||
|
||||
enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
|
||||
|
||||
CTownAndVisitingHero townAndVis;
|
||||
@ -71,7 +73,6 @@ public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGDwelling&>(*this);
|
||||
h & static_cast<IShipyard&>(*this);
|
||||
h & name;
|
||||
h & builded;
|
||||
h & destroyed;
|
||||
@ -134,6 +135,8 @@ public:
|
||||
int getSightRadius() const override; //returns sight distance
|
||||
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
|
||||
EGeneratorState shipyardStatus() const override;
|
||||
const IObjectInterface * getObject() const override;
|
||||
int getMarketEfficiency() const override; //=market count
|
||||
bool allowsTrade(EMarketMode::EMarketMode mode) const override;
|
||||
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
|
||||
@ -197,6 +200,8 @@ public:
|
||||
void battleFinished(const CGHeroInstance * hero, const BattleResult & result) const override;
|
||||
std::string getObjectName() const override;
|
||||
|
||||
void fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const override;
|
||||
|
||||
void afterAddToMap(CMap * map) override;
|
||||
void afterRemoveFromMap(CMap * map) override;
|
||||
static void reset();
|
||||
|
@ -92,10 +92,10 @@ int3 IBoatGenerator::bestLocation() const
|
||||
|
||||
for (auto & offset : offsets)
|
||||
{
|
||||
if(const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
|
||||
if(const TerrainTile *tile = getObject()->cb->getTile(getObject()->getPosition() + offset, false)) //tile is in the map
|
||||
{
|
||||
if(tile->terType->isWater() && (!tile->blocked || tile->blockingObjects.front()->ID == Obj::BOAT)) //and is water and is not blocked or is blocked by boat
|
||||
return o->pos + offset;
|
||||
return getObject()->getPosition() + offset;
|
||||
}
|
||||
}
|
||||
return int3 (-1,-1,-1);
|
||||
@ -107,24 +107,14 @@ IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const
|
||||
const TerrainTile *t = IObjectInterface::cb->getTile(tile);
|
||||
if(!t)
|
||||
return TILE_BLOCKED; //no available water
|
||||
else if(t->blockingObjects.empty())
|
||||
|
||||
if(t->blockingObjects.empty())
|
||||
return GOOD; //OK
|
||||
else if(t->blockingObjects.front()->ID == Obj::BOAT)
|
||||
|
||||
if(t->blockingObjects.front()->ID == Obj::BOAT)
|
||||
return BOAT_ALREADY_BUILT; //blocked with boat
|
||||
else
|
||||
return TILE_BLOCKED; //blocked
|
||||
}
|
||||
|
||||
BoatId IBoatGenerator::getBoatType() const
|
||||
{
|
||||
//We make good ships by default
|
||||
return EBoatId::BOAT_GOOD;
|
||||
}
|
||||
|
||||
|
||||
IBoatGenerator::IBoatGenerator(const CGObjectInstance *O)
|
||||
: o(O)
|
||||
{
|
||||
return TILE_BLOCKED; //blocked
|
||||
}
|
||||
|
||||
void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visitor) const
|
||||
@ -144,7 +134,7 @@ void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visit
|
||||
out.addTxt(MetaString::ADVOB_TXT, 189);
|
||||
break;
|
||||
case NO_WATER:
|
||||
logGlobal->error("Shipyard without water! %s \t %d", o->pos.toString(), o->id.getNum());
|
||||
logGlobal->error("Shipyard without water at tile %s! ", getObject()->getPosition().toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -155,34 +145,9 @@ void IShipyard::getBoatCost(TResources & cost) const
|
||||
cost[EGameResID::GOLD] = 1000;
|
||||
}
|
||||
|
||||
IShipyard::IShipyard(const CGObjectInstance *O)
|
||||
: IBoatGenerator(O)
|
||||
{
|
||||
}
|
||||
|
||||
IShipyard * IShipyard::castFrom( CGObjectInstance *obj )
|
||||
{
|
||||
if(!obj)
|
||||
return nullptr;
|
||||
|
||||
if(obj->ID == Obj::TOWN)
|
||||
{
|
||||
return dynamic_cast<CGTownInstance *>(obj);
|
||||
}
|
||||
else if(obj->ID == Obj::SHIPYARD)
|
||||
{
|
||||
return dynamic_cast<CGShipyard *>(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj )
|
||||
{
|
||||
return castFrom(const_cast<CGObjectInstance*>(obj));
|
||||
return dynamic_cast<const IShipyard *>(obj);
|
||||
}
|
||||
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -14,6 +14,7 @@
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
struct BattleResult;
|
||||
struct UpgradeInfo;
|
||||
class CGObjectInstance;
|
||||
class CRandomGenerator;
|
||||
class IGameCallback;
|
||||
@ -66,42 +67,36 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ICreatureUpgrader
|
||||
{
|
||||
public:
|
||||
virtual void fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const = 0;
|
||||
|
||||
virtual ~ICreatureUpgrader() = default;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IBoatGenerator
|
||||
{
|
||||
public:
|
||||
const CGObjectInstance *o;
|
||||
|
||||
IBoatGenerator(const CGObjectInstance *O);
|
||||
virtual ~IBoatGenerator() = default;
|
||||
|
||||
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 const IObjectInterface * getObject() const = 0;
|
||||
|
||||
virtual BoatId getBoatType() const = 0; //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
|
||||
int3 bestLocation() const; //returns location when the boat should be placed
|
||||
|
||||
enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER};
|
||||
EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water
|
||||
enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER, UNKNOWN};
|
||||
virtual EGeneratorState shipyardStatus() const;
|
||||
void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & o;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IShipyard : public IBoatGenerator
|
||||
{
|
||||
public:
|
||||
IShipyard(const CGObjectInstance *O);
|
||||
|
||||
virtual void getBoatCost(ResourceSet & cost) const;
|
||||
|
||||
static const IShipyard *castFrom(const CGObjectInstance *obj);
|
||||
static IShipyard *castFrom(CGObjectInstance *obj);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<IBoatGenerator&>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -26,6 +26,8 @@
|
||||
#include "../CPlayerState.h"
|
||||
#include "../GameSettings.h"
|
||||
#include "../serializer/JsonSerializeFormat.h"
|
||||
#include "../mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../mapObjectConstructors/CObjectClassesHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@ -1530,7 +1532,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
InfoWindow iw;
|
||||
iw.type = EInfoWindowMode::AUTO;
|
||||
iw.player = h->getOwner();
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,127 + ID - 88);
|
||||
iw.text = visitText;
|
||||
iw.text.addTxt(MetaString::SPELL_NAME,spell);
|
||||
iw.text << ".";
|
||||
|
||||
@ -1542,7 +1544,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,174);
|
||||
}
|
||||
else if(ID == Obj::SHRINE_OF_MAGIC_THOUGHT && h->maxSpellLevel() < 3) //it's third level spell and hero doesn't have wisdom
|
||||
else if(spell.toSpell()->getLevel() > h->maxSpellLevel()) //it's third level spell and hero doesn't have wisdom
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT,130);
|
||||
}
|
||||
@ -1560,20 +1562,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
|
||||
void CGShrine::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
if(spell == SpellID::NONE) //spell not set
|
||||
{
|
||||
int level = ID-87;
|
||||
std::vector<SpellID> possibilities;
|
||||
cb->getAllowedSpells (possibilities, level);
|
||||
|
||||
if(possibilities.empty())
|
||||
{
|
||||
logGlobal->error("Error: cannot init shrine, no allowed spells!");
|
||||
return;
|
||||
}
|
||||
|
||||
spell = *RandomGeneratorUtil::nextItem(possibilities, rand);
|
||||
}
|
||||
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
|
||||
}
|
||||
|
||||
std::string CGShrine::getHoverText(PlayerColor player) const
|
||||
@ -1693,8 +1682,7 @@ void CGScholar::initObj(CRandomGenerator & rand)
|
||||
break;
|
||||
case SPELL:
|
||||
std::vector<SpellID> possibilities;
|
||||
for (int i = 1; i < 6; ++i)
|
||||
cb->getAllowedSpells (possibilities, i);
|
||||
cb->getAllowedSpells (possibilities);
|
||||
bonusID = *RandomGeneratorUtil::nextItem(possibilities, rand);
|
||||
break;
|
||||
}
|
||||
@ -1851,8 +1839,15 @@ void CGMagi::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
h->showInfoDialog(48);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CGBoat::CGBoat()
|
||||
{
|
||||
hero = nullptr;
|
||||
direction = 4;
|
||||
layer = EPathfindingLayer::EEPathfindingLayer::SAIL;
|
||||
}
|
||||
|
||||
void CGBoat::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
hero = nullptr;
|
||||
@ -1927,12 +1922,6 @@ void CGSirens::onHeroVisit( const CGHeroInstance * h ) const
|
||||
}
|
||||
}
|
||||
cb->showInfoDialog(&iw);
|
||||
|
||||
}
|
||||
|
||||
CGShipyard::CGShipyard()
|
||||
:IShipyard(this)
|
||||
{
|
||||
}
|
||||
|
||||
void CGShipyard::getOutOffsets( std::vector<int3> &offsets ) const
|
||||
@ -1947,6 +1936,11 @@ void CGShipyard::getOutOffsets( std::vector<int3> &offsets ) const
|
||||
};
|
||||
}
|
||||
|
||||
const IObjectInterface * CGShipyard::getObject() const
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void CGShipyard::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
if(!cb->gameState()->getPlayerRelations(tempOwner, h->tempOwner))
|
||||
@ -1972,6 +1966,12 @@ void CGShipyard::serializeJsonOptions(JsonSerializeFormat& handler)
|
||||
serializeJsonOwner(handler);
|
||||
}
|
||||
|
||||
BoatId CGShipyard::getBoatType() const
|
||||
{
|
||||
// In H3, external shipyard will always create same boat as castle
|
||||
return EBoatId::CASTLE;
|
||||
}
|
||||
|
||||
void CCartographer::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
//if player has not bought map of this subtype yet and underground exist for stalagmite cartographer
|
||||
@ -2176,4 +2176,26 @@ void CGLighthouse::serializeJsonOptions(JsonSerializeFormat& handler)
|
||||
serializeJsonOwner(handler);
|
||||
}
|
||||
|
||||
void HillFort::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
openWindow(EOpenWindowMode::HILL_FORT_WINDOW,id.getNum(),h->id.getNum());
|
||||
}
|
||||
|
||||
void HillFort::fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const
|
||||
{
|
||||
int32_t level = stack.type->getLevel();
|
||||
int32_t index = std::clamp<int32_t>(level - 1, 0, upgradeCostPercentage.size() - 1);
|
||||
|
||||
int costModifier = upgradeCostPercentage[index];
|
||||
|
||||
if (costModifier < 0)
|
||||
return; // upgrade not allowed
|
||||
|
||||
for(const auto & nid : stack.type->upgrades)
|
||||
{
|
||||
info.newID.push_back(nid);
|
||||
info.cost.push_back((nid.toCreature()->getFullRecruitCost() - stack.type->getFullRecruitCost()) * costModifier / 100);
|
||||
}
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -246,7 +246,9 @@ protected:
|
||||
class DLL_LINKAGE CGShrine : public CTeamVisited
|
||||
{
|
||||
public:
|
||||
MetaString visitText;
|
||||
SpellID spell; //id of spell or NONE if random
|
||||
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj(CRandomGenerator & rand) override;
|
||||
std::string getHoverText(PlayerColor player) const override;
|
||||
@ -256,6 +258,7 @@ public:
|
||||
{
|
||||
h & static_cast<CTeamVisited&>(*this);;
|
||||
h & spell;
|
||||
h & visitText;
|
||||
}
|
||||
protected:
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
@ -429,15 +432,10 @@ public:
|
||||
std::string overlayAnimation; //waves animations
|
||||
std::array<std::string, PlayerColor::PLAYER_LIMIT_I> flagAnimations;
|
||||
|
||||
CGBoat();
|
||||
void initObj(CRandomGenerator & rand) override;
|
||||
static int3 translatePos(const int3 &pos, bool reverse = false);
|
||||
|
||||
CGBoat()
|
||||
{
|
||||
hero = nullptr;
|
||||
direction = 4;
|
||||
layer = EPathfindingLayer::EEPathfindingLayer::SAIL;
|
||||
}
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this);
|
||||
@ -455,16 +453,23 @@ public:
|
||||
|
||||
class DLL_LINKAGE CGShipyard : public CGObjectInstance, public IShipyard
|
||||
{
|
||||
public:
|
||||
void getOutOffsets(std::vector<int3> &offsets) const override; //offsets to obj pos when we boat can be placed
|
||||
CGShipyard();
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
friend class ShipyardInstanceConstructor;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
BoatId createdBoat;
|
||||
|
||||
protected:
|
||||
void getOutOffsets(std::vector<int3> & offsets) const override;
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
const IObjectInterface * getObject() const override;
|
||||
BoatId getBoatType() const override;
|
||||
|
||||
public:
|
||||
template<typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this);
|
||||
h & static_cast<IShipyard&>(*this);
|
||||
h & createdBoat;
|
||||
}
|
||||
|
||||
protected:
|
||||
void serializeJsonOptions(JsonSerializeFormat & handler) override;
|
||||
};
|
||||
@ -550,4 +555,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE HillFort : public CGObjectInstance, public ICreatureUpgrader
|
||||
{
|
||||
friend class HillFortInstanceConstructor;
|
||||
|
||||
std::vector<int> upgradeCostPercentage;
|
||||
|
||||
protected:
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void fillUpgradeInfo(UpgradeInfo & info, const CStackInstance &stack) const override;
|
||||
|
||||
public:
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<CGObjectInstance&>(*this);
|
||||
h & upgradeCostPercentage;
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -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;
|
||||
|
@ -129,9 +129,10 @@ bool TerrainTile::isWater() const
|
||||
}
|
||||
|
||||
CMap::CMap()
|
||||
: checksum(0), grailPos(-1, -1, -1), grailRadius(0), terrain(nullptr),
|
||||
guardingCreaturePositions(nullptr),
|
||||
uidCounter(0)
|
||||
: checksum(0)
|
||||
, grailPos(-1, -1, -1)
|
||||
, grailRadius(0)
|
||||
, uidCounter(0)
|
||||
{
|
||||
allHeroes.resize(allowedHeroes.size());
|
||||
allowedAbilities = VLC->skillh->getDefaultAllowed();
|
||||
@ -142,22 +143,6 @@ CMap::CMap()
|
||||
CMap::~CMap()
|
||||
{
|
||||
getEditManager()->getUndoManager().clearAll();
|
||||
|
||||
if(terrain)
|
||||
{
|
||||
for(int z = 0; z < levels(); z++)
|
||||
{
|
||||
for(int x = 0; x < width; x++)
|
||||
{
|
||||
delete[] terrain[z][x];
|
||||
delete[] guardingCreaturePositions[z][x];
|
||||
}
|
||||
delete[] terrain[z];
|
||||
delete[] guardingCreaturePositions[z];
|
||||
}
|
||||
delete [] terrain;
|
||||
delete [] guardingCreaturePositions;
|
||||
}
|
||||
|
||||
for(auto obj : objects)
|
||||
obj.dellNull();
|
||||
@ -572,19 +557,8 @@ void CMap::removeObject(CGObjectInstance * obj)
|
||||
|
||||
void CMap::initTerrain()
|
||||
{
|
||||
int level = levels();
|
||||
terrain = new TerrainTile**[level];
|
||||
guardingCreaturePositions = new int3**[level];
|
||||
for(int z = 0; z < level; ++z)
|
||||
{
|
||||
terrain[z] = new TerrainTile*[width];
|
||||
guardingCreaturePositions[z] = new int3*[width];
|
||||
for(int x = 0; x < width; ++x)
|
||||
{
|
||||
terrain[z][x] = new TerrainTile[height];
|
||||
guardingCreaturePositions[z][x] = new int3[height];
|
||||
}
|
||||
}
|
||||
terrain.resize(boost::extents[levels()][width][height]);
|
||||
guardingCreaturePositions.resize(boost::extents[levels()][width][height]);
|
||||
}
|
||||
|
||||
CMapEditManager * CMap::getEditManager()
|
||||
|
@ -142,14 +142,14 @@ public:
|
||||
std::map<si32, ObjectInstanceID> questIdentifierToId;
|
||||
|
||||
std::unique_ptr<CMapEditManager> editManager;
|
||||
|
||||
int3 ***guardingCreaturePositions;
|
||||
boost::multi_array<int3, 3> guardingCreaturePositions;
|
||||
|
||||
std::map<std::string, ConstTransitivePtr<CGObjectInstance> > instanceNames;
|
||||
|
||||
private:
|
||||
/// a 3-dimensional array of terrain tiles, access is as follows: x, y, level. where level=1 is underground
|
||||
TerrainTile*** terrain;
|
||||
boost::multi_array<TerrainTile, 3> terrain;
|
||||
|
||||
si32 uidCounter; //TODO: initialize when loading an old map
|
||||
|
||||
public:
|
||||
@ -170,50 +170,8 @@ public:
|
||||
h & questIdentifierToId;
|
||||
|
||||
//TODO: viccondetails
|
||||
const int level = levels();
|
||||
if(h.saving)
|
||||
{
|
||||
// Save terrain
|
||||
for(int z = 0; z < level; ++z)
|
||||
{
|
||||
for(int x = 0; x < width; ++x)
|
||||
{
|
||||
for(int y = 0; y < height; ++y)
|
||||
{
|
||||
h & terrain[z][x][y];
|
||||
h & guardingCreaturePositions[z][x][y];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Load terrain
|
||||
terrain = new TerrainTile**[level];
|
||||
guardingCreaturePositions = new int3**[level];
|
||||
for(int z = 0; z < level; ++z)
|
||||
{
|
||||
terrain[z] = new TerrainTile*[width];
|
||||
guardingCreaturePositions[z] = new int3*[width];
|
||||
for(int x = 0; x < width; ++x)
|
||||
{
|
||||
terrain[z][x] = new TerrainTile[height];
|
||||
guardingCreaturePositions[z][x] = new int3[height];
|
||||
}
|
||||
}
|
||||
for(int z = 0; z < level; ++z)
|
||||
{
|
||||
for(int x = 0; x < width; ++x)
|
||||
{
|
||||
for(int y = 0; y < height; ++y)
|
||||
{
|
||||
|
||||
h & terrain[z][x][y];
|
||||
h & guardingCreaturePositions[z][x][y];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
h & terrain;
|
||||
h & guardingCreaturePositions;
|
||||
|
||||
h & objects;
|
||||
h & heroesOnMap;
|
||||
|
@ -1292,9 +1292,9 @@ CGObjectInstance * CMapLoaderH3M::readQuestGuard(const int3 & mapPosition)
|
||||
return guard;
|
||||
}
|
||||
|
||||
CGObjectInstance * CMapLoaderH3M::readShipyard(const int3 & mapPosition)
|
||||
CGObjectInstance * CMapLoaderH3M::readShipyard(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate)
|
||||
{
|
||||
auto * object = new CGShipyard();
|
||||
auto * object = readGeneric(mapPosition, objectTemplate);
|
||||
setOwnerAndValidate(mapPosition, object, reader->readPlayer32());
|
||||
return object;
|
||||
}
|
||||
@ -1448,7 +1448,7 @@ CGObjectInstance * CMapLoaderH3M::readObject(std::shared_ptr<const ObjectTemplat
|
||||
return readQuestGuard(mapPosition);
|
||||
|
||||
case Obj::SHIPYARD:
|
||||
return readShipyard(mapPosition);
|
||||
return readShipyard(mapPosition, objectTemplate);
|
||||
|
||||
case Obj::HERO_PLACEHOLDER:
|
||||
return readHeroPlaceholder(mapPosition);
|
||||
|
@ -180,7 +180,7 @@ private:
|
||||
CGObjectInstance * readBorderGuard();
|
||||
CGObjectInstance * readBorderGate(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
|
||||
CGObjectInstance * readQuestGuard(const int3 & position);
|
||||
CGObjectInstance * readShipyard(const int3 & mapPosition);
|
||||
CGObjectInstance * readShipyard(const int3 & mapPosition, std::shared_ptr<const ObjectTemplate> objectTemplate);
|
||||
CGObjectInstance * readLighthouse(const int3 & mapPosition);
|
||||
CGObjectInstance * readGeneric(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
|
||||
CGObjectInstance * readBank(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
|
||||
|
@ -20,6 +20,11 @@
|
||||
#include "../CModHandler.h" //needed?
|
||||
#include "../mapObjectConstructors/CRewardableConstructor.h"
|
||||
#include "../mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../mapObjectConstructors/CBankInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/DwellingInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/HillFortInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/ShipyardInstanceConstructor.h"
|
||||
#include "../mapObjectConstructors/ShrineInstanceConstructor.h"
|
||||
#include "../mapObjects/MapObjects.h"
|
||||
#include "../mapObjects/CGTownBuilding.h"
|
||||
#include "../mapObjects/ObjectTemplate.h"
|
||||
@ -59,10 +64,11 @@ void registerTypesMapObjects1(Serializer &s)
|
||||
s.template registerType<CGObjectInstance, CGBoat>();
|
||||
s.template registerType<CGObjectInstance, CGMagi>();
|
||||
s.template registerType<CGObjectInstance, CGSirens>();
|
||||
s.template registerType<CGObjectInstance, CGShipyard>(); s.template registerType<IShipyard, CGShipyard>();
|
||||
s.template registerType<CGObjectInstance, CGShipyard>();
|
||||
s.template registerType<CGObjectInstance, CGDenOfthieves>();
|
||||
s.template registerType<CGObjectInstance, CGLighthouse>();
|
||||
s.template registerType<CGObjectInstance, CGTerrainPatch>();
|
||||
s.template registerType<CGObjectInstance, HillFort>();
|
||||
s.template registerType<CGObjectInstance, CGMarket>();
|
||||
s.template registerType<CGMarket, CGBlackMarket>();
|
||||
s.template registerType<CGMarket, CGUniversity>();
|
||||
@ -71,9 +77,9 @@ void registerTypesMapObjects1(Serializer &s)
|
||||
s.template registerType<CGObjectInstance, CArmedInstance>(); s.template registerType<CBonusSystemNode, CArmedInstance>(); s.template registerType<CCreatureSet, CArmedInstance>();
|
||||
|
||||
// Armed objects
|
||||
s.template registerType<CArmedInstance, CGHeroInstance>(); s.template registerType<IBoatGenerator, CGHeroInstance>(); s.template registerType<CArtifactSet, CGHeroInstance>();
|
||||
s.template registerType<CArmedInstance, CGHeroInstance>(); s.template registerType<CArtifactSet, CGHeroInstance>();
|
||||
s.template registerType<CArmedInstance, CGDwelling>();
|
||||
s.template registerType<CGDwelling, CGTownInstance>(); s.template registerType<IShipyard, CGTownInstance>();
|
||||
s.template registerType<CGDwelling, CGTownInstance>();
|
||||
s.template registerType<CArmedInstance, CGPandoraBox>();
|
||||
s.template registerType<CGPandoraBox, CGEvent>();
|
||||
s.template registerType<CArmedInstance, CGCreature>();
|
||||
@ -92,11 +98,14 @@ void registerTypesMapObjectTypes(Serializer &s)
|
||||
s.template registerType<AObjectTypeHandler, CRewardableConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, CHeroInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, CTownInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, CDwellingInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, DwellingInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, CBankInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, BoatInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, MarketInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, CObstacleConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, ShrineInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, ShipyardInstanceConstructor>();
|
||||
s.template registerType<AObjectTypeHandler, HillFortInstanceConstructor>();
|
||||
|
||||
#define REGISTER_GENERIC_HANDLER(TYPENAME) s.template registerType<AObjectTypeHandler, CDefaultObjectTypeHandler<TYPENAME> >()
|
||||
|
||||
@ -137,6 +146,7 @@ void registerTypesMapObjectTypes(Serializer &s)
|
||||
REGISTER_GENERIC_HANDLER(CGTownInstance);
|
||||
REGISTER_GENERIC_HANDLER(CGUniversity);
|
||||
REGISTER_GENERIC_HANDLER(CGWitchHut);
|
||||
REGISTER_GENERIC_HANDLER(HillFort);
|
||||
|
||||
#undef REGISTER_GENERIC_HANDLER
|
||||
|
||||
|
@ -74,8 +74,7 @@ Rewardable::LimitersList Rewardable::Info::configureSublimiters(Rewardable::Conf
|
||||
void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRandomGenerator & rng, Rewardable::Limiter & limiter, const JsonNode & source) const
|
||||
{
|
||||
std::vector<SpellID> spells;
|
||||
for (size_t i=0; i<6; i++)
|
||||
IObjectInterface::cb->getAllowedSpells(spells, static_cast<ui16>(i));
|
||||
IObjectInterface::cb->getAllowedSpells(spells);
|
||||
|
||||
|
||||
limiter.dayOfWeek = JsonRandom::loadValue(source["dayOfWeek"], rng);
|
||||
@ -124,8 +123,7 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRand
|
||||
reward.secondary = JsonRandom::loadSecondary(source["secondary"], rng);
|
||||
|
||||
std::vector<SpellID> spells;
|
||||
for (size_t i=0; i<6; i++)
|
||||
IObjectInterface::cb->getAllowedSpells(spells, static_cast<ui16>(i));
|
||||
IObjectInterface::cb->getAllowedSpells(spells);
|
||||
|
||||
reward.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng);
|
||||
reward.spells = JsonRandom::loadSpells(source["spells"], rng, spells);
|
||||
|
@ -22,7 +22,8 @@
|
||||
#include "../../ArtifactUtils.h"
|
||||
#include "../../mapObjectConstructors/AObjectTypeHandler.h"
|
||||
#include "../../mapObjectConstructors/CObjectClassesHandler.h"
|
||||
#include "../../mapObjectConstructors/CommonConstructors.h"
|
||||
#include "../../mapObjectConstructors/DwellingInstanceConstructor.h"
|
||||
#include "../../mapObjects/CGHeroInstance.h"
|
||||
#include "../../mapObjects/CGPandoraBox.h"
|
||||
#include "../../CCreatureHandler.h"
|
||||
#include "../../spells/CSpellHandler.h" //for choosing random spells
|
||||
@ -171,7 +172,7 @@ void TreasurePlacer::addAllPossibleObjects()
|
||||
|
||||
for(auto secondaryID : subObjects)
|
||||
{
|
||||
const auto * dwellingHandler = dynamic_cast<const CDwellingInstanceConstructor *>(VLC->objtypeh->getHandlerFor(dwellingType, secondaryID).get());
|
||||
const auto * dwellingHandler = dynamic_cast<const DwellingInstanceConstructor *>(VLC->objtypeh->getHandlerFor(dwellingType, secondaryID).get());
|
||||
auto creatures = dwellingHandler->getProducedCreatures();
|
||||
if(creatures.empty())
|
||||
continue;
|
||||
|
@ -215,7 +215,7 @@ ESpellCastResult SummonBoatMechanics::applyAdventureEffects(SpellCastEnvironment
|
||||
{
|
||||
NewObject no;
|
||||
no.ID = Obj::BOAT;
|
||||
no.subID = BoatId(EBoatId::BOAT_EVIL);
|
||||
no.subID = BoatId(EBoatId::NECROPOLIS);
|
||||
no.pos = CGBoat::translatePos(summonPos);
|
||||
env->apply(&no);
|
||||
}
|
||||
|
@ -127,6 +127,11 @@ int64_t CSpell::calculateDamage(const spells::Caster * caster) const
|
||||
return caster->getSpellBonus(this, rawDamage, nullptr);
|
||||
}
|
||||
|
||||
bool CSpell::hasSchool(ESpellSchool which) const
|
||||
{
|
||||
return school.count(which) && school.at(which);
|
||||
}
|
||||
|
||||
bool CSpell::canBeCast(const CBattleInfoCallback * cb, spells::Mode mode, const spells::Caster * caster) const
|
||||
{
|
||||
//if caller do not interested in description just discard it and do not pollute even debug log
|
||||
|
@ -209,6 +209,8 @@ public:
|
||||
|
||||
int64_t calculateDamage(const spells::Caster * caster) const override;
|
||||
|
||||
bool hasSchool(ESpellSchool school) const override;
|
||||
|
||||
/**
|
||||
* Calls cb for each school this spell belongs to
|
||||
*
|
||||
|
@ -4421,7 +4421,7 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, PlayerColor pl
|
||||
//Create a new boat for hero
|
||||
NewObject no;
|
||||
no.ID = Obj::BOAT;
|
||||
no.subID = BoatId(EBoatId::BOAT_NEUTRAL);
|
||||
no.subID = BoatId(EBoatId::CASTLE);
|
||||
no.pos = hr.tile + int3(1,0,0);
|
||||
sendAndApply(&no);
|
||||
|
||||
@ -5627,12 +5627,6 @@ bool CGameHandler::buildBoat(ObjectInstanceID objid, PlayerColor playerID)
|
||||
complain("Cannot build boat in this shipyard!");
|
||||
return false;
|
||||
}
|
||||
else if (obj->o->ID == Obj::TOWN
|
||||
&& !static_cast<const CGTownInstance*>(obj)->hasBuilt(BuildingID::SHIPYARD))
|
||||
{
|
||||
complain("Cannot build boat in the town - no shipyard!");
|
||||
return false;
|
||||
}
|
||||
|
||||
TResources boatCost;
|
||||
obj->getBoatCost(boatCost);
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
MOCK_CONST_METHOD0(isOffensive, bool());
|
||||
MOCK_CONST_METHOD0(isSpecial, bool());
|
||||
MOCK_CONST_METHOD0(isMagical, bool());
|
||||
MOCK_CONST_METHOD1(hasSchool, bool(ESpellSchool));
|
||||
MOCK_CONST_METHOD1(forEachSchool, void(const SchoolCallback &));
|
||||
MOCK_CONST_METHOD0(getCastSound, const std::string &());
|
||||
MOCK_CONST_METHOD1(registerIcons, void(const IconRegistar &));
|
||||
|
Loading…
x
Reference in New Issue
Block a user