1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-21 17:17:06 +02:00

battlefields in VLC and custom bonuses for terrain patches

This commit is contained in:
Andrii Danylchenko 2022-06-28 11:05:30 +03:00
parent 3b1d271ae0
commit 4b4cc3cf4b
47 changed files with 645 additions and 221 deletions

View File

@ -37,6 +37,7 @@ void CGameInfo::setFromLib()
spellh = VLC->spellh;
skillh = VLC->skillh;
objtypeh = VLC->objtypeh;
battleFieldHandler = VLC->battlefieldsHandler;
}
const ArtifactService * CGameInfo::artifacts() const
@ -44,6 +45,11 @@ const ArtifactService * CGameInfo::artifacts() const
return globalServices->artifacts();
}
const BattleFieldService * CGameInfo::battlefields() const
{
return globalServices->battlefields();
}
const CreatureService * CGameInfo::creatures() const
{
return globalServices->creatures();

View File

@ -31,6 +31,7 @@ class CCursorHandler;
class CGameState;
class IMainVideoPlayer;
class CServerHandler;
class BattleFieldHandler;
class CMap;
@ -60,6 +61,7 @@ public:
const scripting::Service * scripts() const override;
const spells::Service * spells() const override;
const SkillService * skills() const override;
const BattleFieldService * battlefields() const override;
void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
@ -68,6 +70,7 @@ public:
ConstTransitivePtr<CModHandler> modh; //public?
ConstTransitivePtr<BattleFieldHandler> battleFieldHandler;
ConstTransitivePtr<CHeroHandler> heroh;
ConstTransitivePtr<CCreatureHandler> creh;
ConstTransitivePtr<CSpellHandler> spellh;

View File

@ -109,12 +109,6 @@ void Graphics::initializeBattleGraphics()
const JsonNode config(mod, ResourceID("config/battles_graphics.json"));
if(!config["backgrounds"].isNull())
for(auto & t : config["backgrounds"].Struct())
{
battleBacks[t.first] = t.second.String();
}
//initialization of AC->def name mapping
if(!config["ac_mapping"].isNull())
for(const JsonNode &ac : config["ac_mapping"].Vector())

View File

@ -87,7 +87,6 @@ public:
//towns
std::map<int, std::string> ERMUtoPicture[GameConstants::F_NUMBER]; //maps building ID to it's picture's name for each town type
//for battles
std::map<std::string, std::string> battleBacks; //maps BattleField to it's picture's name
std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names
//functions

View File

@ -41,6 +41,7 @@
#include "../../lib/spells/ISpellMechanics.h"
#include "../../lib/spells/Problem.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/BattleFieldHandler.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"
#include "../../lib/NetPacks.h"
@ -201,13 +202,14 @@ CBattleInterface::CBattleInterface(const CCreatureSet *army1, const CCreatureSet
else
{
auto bfieldType = curInt->cb->battleGetBattlefieldType();
if(!vstd::contains(graphics->battleBacks, bfieldType))
if(bfieldType == BattleField::NONE)
{
logGlobal->error("%s is not valid battlefield type!", static_cast<std::string>(bfieldType));
logGlobal->error("Invalid battlefield returned for current battle");
}
else
{
background = BitmapHandler::loadBitmap(graphics->battleBacks[bfieldType], false);
background = BitmapHandler::loadBitmap(bfieldType.getInfo()->graphics, false);
}
}

173
config/battlefields.json Normal file
View File

@ -0,0 +1,173 @@
{
"sand_shore": { "graphics" : "CMBKBCH.BMP" },
"sand_mesas": { "graphics" : "CMBKDES.BMP" },
"dirt_birches": { "graphics" : "CMBKDRTR.BMP" },
"dirt_hills": { "graphics" : "CMBKDRMT.BMP" },
"dirt_pines": { "graphics" : "CMBKDRDD.BMP" },
"grass_hills": { "graphics" : "CMBKGRMT.BMP" },
"grass_pines": { "graphics" : "CMBKGRTR.BMP" },
"lava": { "graphics" :"CMBKLAVA.BMP" },
"magic_plains": {
"graphics": "CMBKMAG.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MAGIC_SCHOOL_SKILL",
"subtype" : 0,
"val" : 3,
"valueType" : "BASE_NUMBER"
}
]
},
"snow_mountains": { "graphics" : "CMBKSNMT.BMP" },
"snow_trees": { "graphics" : "CMBKSNTR.BMP" },
"subterranean": { "graphics" : "CMBKSUB.BMP", "isSpecial" : true },
"swamp_trees": { "graphics" : "CMBKSWMP.BMP" },
"fiery_fields": {
"graphics": "CMBKFF.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MAGIC_SCHOOL_SKILL",
"subtype" : 2,
"val" : 3,
"valueType" : "BASE_NUMBER"
}
]
},
"rocklands": {
"graphics": "CMBKRK.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MAGIC_SCHOOL_SKILL",
"subtype" : 8,
"val" : 3,
"valueType" : "BASE_NUMBER"
}
]
},
"magic_clouds": {
"graphics": "CMBKMC.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MAGIC_SCHOOL_SKILL",
"subtype" : 1,
"val" : 3,
"valueType" : "BASE_NUMBER"
}
]
},
"lucid_pools": {
"graphics": "CMBKLP.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MAGIC_SCHOOL_SKILL",
"subtype" : 4,
"val" : 3,
"valueType" : "BASE_NUMBER"
}
]
},
"holy_ground": {
"graphics": "CMBKHG.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MORALE",
"val" : 1,
"valueType" : "BASE_NUMBER",
"description" : "Creatures of good town alignment on Holly Ground",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }]
},
{
"type" : "MORALE",
"val" : -1,
"valueType" : "BASE_NUMBER",
"description" : "Creatures of evil town alignment on Holly Ground",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }]
}
]
},
"clover_field": {
"graphics": "CMBKCF.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "LUCK",
"val" : 2,
"valueType" : "BASE_NUMBER",
"description" : "Creatures of neutral town alignment on Clover Field",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["neutral"] }]
}
]
},
"evil_fog": {
"graphics": "CMBKEF.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "MORALE",
"val" : -1,
"valueType" : "BASE_NUMBER",
"description" : "Creatures of good town alignment on Evil Fog",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["good"] }]
},
{
"type" : "MORALE",
"val" : 1,
"valueType" : "BASE_NUMBER",
"description" : "Creatures of evil town alignment on Evil Fog",
"limiters": [{ "type" : "CREATURE_ALIGNMENT_LIMITER", "parameters" : ["evil"] }]
}
]
},
"favorable_winds": {
"graphics": "CMBKFW.BMP",
"isSpecial" : true
},
"cursed_ground": {
"graphics": "CMBKCUR.BMP",
"isSpecial" : true,
"bonuses": [
{
"type" : "NO_MORALE",
"subtype" : 0,
"val" : 0,
"valueType" : "INDEPENDENT_MIN",
"description" : "Creatures on Cursed Ground"
},
{
"type" : "NO_LUCK",
"subtype" : 0,
"val" : 0,
"valueType" : "INDEPENDENT_MIN",
"description" : "Creatures on Cursed Ground"
},
{
"type" : "BLOCK_MAGIC_ABOVE",
"subtype" : 0,
"val" : 1,
"valueType" : "INDEPENDENT_MIN"
}
]
},
"rough": { "graphics" : "CMBKRGH.BMP" },
"ship_to_ship":
{
"graphics" : "CMBKBOAT.BMP"
"impassableHexes" : [
6, 7, 8, 9,
24, 25, 26,
58, 59, 60,
75, 76, 77,
92, 93, 94,
109, 110, 111,
126, 127, 128,
159, 160, 161, 162, 163,
176, 177, 178, 179, 180]
},
"ship": { "graphics" : "CMBKDECK.BMP" }
}

View File

@ -1,33 +1,4 @@
{
// backgrounds of terrains battles can be fought on
"backgrounds": {
"sand_shore": "CMBKBCH.BMP",
"sand_mesas": "CMBKDES.BMP",
"dirt_birches": "CMBKDRTR.BMP",
"dirt_hills": "CMBKDRMT.BMP",
"dirt_pines": "CMBKDRDD.BMP",
"grass_hills": "CMBKGRMT.BMP",
"grass_pines": "CMBKGRTR.BMP",
"lava": "CMBKLAVA.BMP",
"magic_plains": "CMBKMAG.BMP",
"snow_mountains": "CMBKSNMT.BMP",
"snow_trees": "CMBKSNTR.BMP",
"subterranean": "CMBKSUB.BMP",
"swamp_trees": "CMBKSWMP.BMP",
"fiery_fields": "CMBKFF.BMP",
"rocklands": "CMBKRK.BMP",
"magic_clouds": "CMBKMC.BMP",
"lucid_pools": "CMBKLP.BMP",
"holy_ground": "CMBKHG.BMP",
"clover_field": "CMBKCF.BMP",
"evil_fog": "CMBKEF.BMP",
"favorable_winds": "CMBKFW.BMP",
"cursed_ground": "CMBKCUR.BMP",
"rough": "CMBKRGH.BMP",
"ship_to_ship": "CMBKBOAT.BMP",
"ship": "CMBKDECK.BMP"
},
// WoG_Ac_format_to_def_names_mapping
"ac_mapping": [
{ "id": 0, "defnames": [ "C10SPW.DEF" ] },//merged

View File

@ -84,5 +84,9 @@
"terrains":
[
"config/terrains.json"
],
"battlefields":
[
"config/battlefields.json"
]
}

View File

@ -0,0 +1,35 @@
{
"type":"object",
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI battlefield format",
"description" : "Format used to define new artifacts in VCMI",
"required" : [ "graphics" ],
"additionalProperties" : false,
"properties":{
"bonuses": {
"type":"array",
"description": "Bonuses provided by this battleground using bonus system",
"items": { "$ref" : "bonus.json" }
},
"name": {
"type":"string",
"description": "Name of the battleground"
},
"graphics": {
"type":"string",
"description": "BMP battleground resource"
},
"isSpecial": {
"type":"boolean",
"description": "Shows if this battleground has own obstacles"
},
"impassableHexes": {
"type":"array",
"description": "Battle hexes always impassable for this type of battlefield (ship to ship for instance)",
"items": {
"type":"number"
}
}
}
}

View File

@ -112,6 +112,12 @@
"description": "List of configuration files for RMG templates",
"items": { "type":"string", "format" : "textFile" }
},
"battlefields":{
"type":"array",
"description": "List of configuration files for battlefields",
"items": { "type":"string", "format" : "textFile" }
},
"changelog" : {

View File

@ -19,6 +19,7 @@ class HeroClassService;
class HeroTypeService;
class SkillService;
class JsonNode;
class BattleFieldService;
namespace spells
{
@ -48,6 +49,7 @@ public:
virtual const scripting::Service * scripts() const = 0;
virtual const spells::Service * spells() const = 0;
virtual const SkillService * skills() const = 0;
virtual const BattleFieldService * battlefields() const = 0;
virtual void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) = 0;

108
lib/BattleFieldHandler.cpp Normal file
View File

@ -0,0 +1,108 @@
/*
* BattleFieldHandler.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
*
*/
#include "StdInc.h"
#include <vcmi/Entity.h>
#include "BattleFieldHandler.h"
BattleFieldInfo * BattleFieldHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index)
{
BattleFieldInfo * info = new BattleFieldInfo(BattleField(index), identifier);
if(json["graphics"].getType() == JsonNode::JsonType::DATA_STRING)
{
info->graphics = json["graphics"].String();
}
if(json["icon"].getType() == JsonNode::JsonType::DATA_STRING)
{
info->icon = json["icon"].String();
}
if(json["name"].getType() == JsonNode::JsonType::DATA_STRING)
{
info->name = json["name"].String();
}
if(json["bonuses"].getType() == JsonNode::JsonType::DATA_VECTOR)
{
for(auto b : json["bonuses"].Vector())
{
auto bonus = JsonUtils::parseBonus(b);
bonus->source = Bonus::TERRAIN_OVERLAY;
bonus->sid = info->getIndex();
bonus->duration = Bonus::ONE_BATTLE;
info->bonuses.push_back(bonus);
}
}
if(json["isSpecial"].getType() == JsonNode::JsonType::DATA_BOOL)
{
info->isSpecial = json["isSpecial"].Bool();
}
if(json["impassableHexes"].getType() == JsonNode::JsonType::DATA_VECTOR)
{
for(auto node : json["impassableHexes"].Vector())
info->impassableHexes.push_back(BattleHex(node.Integer()));
}
return info;
}
std::vector<JsonNode> BattleFieldHandler::loadLegacyData(size_t dataSize)
{
return std::vector<JsonNode>();
}
const std::vector<std::string> & BattleFieldHandler::getTypeNames() const
{
static const std::vector<std::string> types = std::vector<std::string> { "battlefield" };
return types;
}
std::vector<bool> BattleFieldHandler::getDefaultAllowed() const
{
return std::vector<bool>();
}
int32_t BattleFieldInfo::getIndex() const
{
return battlefield.getNum();
}
int32_t BattleFieldInfo::getIconIndex() const
{
return iconIndex;
}
const std::string & BattleFieldInfo::getName() const
{
return name;
}
const std::string & BattleFieldInfo::getJsonKey() const
{
return identifier;
}
void BattleFieldInfo::registerIcons(const IconRegistar & cb) const
{
//cb(getIconIndex(), "BATTLEFIELD", icon);
}
BattleField BattleFieldInfo::getId() const
{
return battlefield;
}

85
lib/BattleFieldHandler.h Normal file
View File

@ -0,0 +1,85 @@
/*
* BattleFieldHandler.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 <vcmi/EntityService.h>
#include "HeroBonus.h"
#include "GameConstants.h"
#include "IHandlerBase.h"
#include "Terrain.h"
#include "battle/BattleHex.h"
class BattleFieldInfo : public EntityT<BattleField>
{
public:
BattleField battlefield;
std::vector<std::shared_ptr<Bonus>> bonuses;
bool isSpecial;
std::string graphics;
std::string name;
std::string identifier;
std::string icon;
si32 iconIndex;
std::vector<BattleHex> impassableHexes;
BattleFieldInfo()
: BattleFieldInfo(BattleField::NONE, "")
{
}
BattleFieldInfo(BattleField battlefield, std::string identifier)
:bonuses(), isSpecial(false), battlefield(battlefield), identifier(identifier), graphics(), icon(), iconIndex(battlefield.getNum()), impassableHexes(), name(identifier)
{
}
int32_t getIndex() const override;
int32_t getIconIndex() const override;
const std::string & getName() const override;
const std::string & getJsonKey() const override;
void registerIcons(const IconRegistar & cb) const override;
BattleField getId() const override;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & name;
h & identifier;
h & isSpecial;
h & graphics;
h & icon;
h & iconIndex;
h & battlefield;
h & impassableHexes;
}
};
class DLL_LINKAGE BattleFieldService : public EntityServiceT<BattleField, BattleFieldInfo>
{
public:
};
class BattleFieldHandler : public CHandlerBase<BattleField, BattleFieldInfo, BattleFieldInfo, BattleFieldService>
{
public:
virtual BattleFieldInfo * loadFromJson(
const std::string & scope,
const JsonNode & json,
const std::string & identifier,
size_t index) override;
virtual const std::vector<std::string> & getTypeNames() const override;
virtual std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
virtual std::vector<bool> getDefaultAllowed() const override;
template <typename Handler> void serialize(Handler & h, const int version)
{
h & objects;
}
};

View File

@ -1922,9 +1922,10 @@ BattleField CGameState::battleGetBattlefieldType(int3 tile, CRandomGenerator & r
}
if(map->isCoastalTile(tile)) //coastal tile is always ground
return BattleField("sand_shore");
return BattleField::fromString("sand_shore");
return *RandomGeneratorUtil::nextItem(Terrain::Manager::getInfo(t.terType).battleFields, rand);
return BattleField::fromString(
*RandomGeneratorUtil::nextItem(Terrain::Manager::getInfo(t.terType).battleFields, rand));
}
UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)

View File

@ -25,6 +25,7 @@
#include <math.h>
#include "mapObjects/CObjectClassesHandler.h"
#include "BattleFieldHandler.h"
CHero::CHero() = default;
CHero::~CHero() = default;
@ -179,8 +180,10 @@ std::vector<BattleHex> CObstacleInfo::getBlocked(BattleHex hex) const
bool CObstacleInfo::isAppropriate(const Terrain & terrainType, const BattleField & battlefield) const
{
if(battlefield.isSpecial())
return vstd::contains(allowedSpecialBfields, battlefield);
auto bgInfo = battlefield.getInfo();
if(bgInfo->isSpecial)
return vstd::contains(allowedSpecialBfields, bgInfo->identifier);
return vstd::contains(allowedTerrains, terrainType);
}

View File

@ -227,7 +227,7 @@ struct DLL_LINKAGE CObstacleInfo
{
std::string defName;
std::vector<Terrain> allowedTerrains;
std::vector<BattleField> allowedSpecialBfields;
std::vector<std::string> allowedSpecialBfields;
ui8 isAbsoluteObstacle; //there may only one such obstacle in battle and its position is always the same
si32 width, height; //how much space to the right and up is needed to place obstacle (affects only placement algorithm)

View File

@ -129,7 +129,8 @@ set(lib_SRCS
spells/effects/Sacrifice.cpp
vstd/StringUtils.cpp
BattleFieldHandler.cpp
CAndroidVMHelper.cpp
CArtHandler.cpp
CBonusTypeHandler.cpp
@ -338,6 +339,7 @@ set(lib_HEADERS
spells/effects/Sacrifice.h
AI_Base.h
BattleFieldHandler.h
CAndroidVMHelper.h
CArtHandler.h
CBonusTypeHandler.h

View File

@ -25,6 +25,7 @@
#include "spells/CSpellHandler.h"
#include "CSkillHandler.h"
#include "ScriptHandler.h"
#include "BattleFieldHandler.h"
#include <vstd/StringUtils.h>
@ -433,6 +434,7 @@ void CContentHandler::init()
handlers.insert(std::make_pair("skills", ContentTypeHandler(VLC->skillh, "skill")));
handlers.insert(std::make_pair("templates", ContentTypeHandler((IHandlerBase *)VLC->tplh, "template")));
handlers.insert(std::make_pair("scripts", ContentTypeHandler(VLC->scriptHandler, "script")));
handlers.insert(std::make_pair("battlefields", ContentTypeHandler(VLC->battlefieldsHandler, "battlefield")));
//TODO: any other types of moddables?
}

View File

@ -34,6 +34,7 @@
#include "StringConstants.h"
#include "CGeneralTextHandler.h"
#include "CModHandler.h"//todo: remove
#include "BattleFieldHandler.h"
const SlotID SlotID::COMMANDER_SLOT_PLACEHOLDER = SlotID(-2);
const SlotID SlotID::SUMMONED_SLOT_PLACEHOLDER = SlotID(-3);
@ -255,3 +256,40 @@ std::ostream & operator<<(std::ostream & os, const EPathfindingLayer pathfinding
if (it == pathfinderLayerToString.end()) return os << "<Unknown type>";
else return os << it->second;
}
const BattleField BattleField::NONE;
bool operator==(const BattleField & l, const BattleField & r)
{
return l.num == r.num;
}
bool operator!=(const BattleField & l, const BattleField & r)
{
return l.num != r.num;
}
bool operator<(const BattleField & l, const BattleField & r)
{
return l.num < r.num;
}
BattleField::operator std::string() const
{
return getInfo()->identifier;
}
const BattleFieldInfo * BattleField::getInfo() const
{
return VLC->battlefields()->getById(*this);
}
BattleField BattleField::fromString(std::string identifier)
{
auto rawId = VLC->modh->identifiers.getIdentifier("core", "battlefield", identifier);
if(rawId)
return BattleField(rawId.get());
else
return BattleField::NONE;
}

View File

@ -1109,6 +1109,23 @@ public:
ID_LIKE_OPERATORS(SpellID, SpellID::ESpellID)
class BattleFieldInfo;
class BattleField : public BaseForID<BattleField, si32>
{
INSTID_LIKE_CLASS_COMMON(BattleField, si32)
DLL_LINKAGE static const BattleField NONE;
DLL_LINKAGE friend bool operator==(const BattleField & l, const BattleField & r);
DLL_LINKAGE friend bool operator!=(const BattleField & l, const BattleField & r);
DLL_LINKAGE friend bool operator<(const BattleField & l, const BattleField & r);
DLL_LINKAGE operator std::string() const;
DLL_LINKAGE const BattleFieldInfo * getInfo() const;
DLL_LINKAGE static BattleField fromString(std::string identifier);
};
enum class ESpellSchool: ui8
{
AIR = 0,

View File

@ -16,6 +16,7 @@
#include "NetPacks.h"
#include "CBonusTypeHandler.h"
#include "CModHandler.h"
#include "BattleFieldHandler.h"
#include "serializer/CSerializer.h" // for SAVEGAME_MAGIC
#include "serializer/BinaryDeserializer.h"

View File

@ -18,8 +18,6 @@
const Terrain Terrain::ANY("ANY");
const BattleField BattleField::NONE("");
Terrain Terrain::createTerrainTypeH3M(int tId)
{
static std::array<std::string, 10> terrainsH3M
@ -227,27 +225,3 @@ bool Terrain::isTransitionRequired() const
{
return Terrain::Manager::getInfo(*this).transitionRequired;
}
bool operator==(const BattleField & l, const BattleField & r)
{
return l.name == r.name;
}
bool operator!=(const BattleField & l, const BattleField & r)
{
return l.name != r.name;
}
bool operator<(const BattleField & l, const BattleField & r)
{
return l.name < r.name;
}
BattleField::operator std::string() const
{
return name;
}
int BattleField::hash() const
{
return std::hash<std::string>{}(name);
}

View File

@ -11,47 +11,9 @@
#pragma once
#include "ConstTransitivePtr.h"
#include "GameConstants.h"
#include "JsonNode.h"
class DLL_LINKAGE BattleField
{
public:
// 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines
//8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields
//15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog
//21. "favorable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
/*enum EBFieldType {NONE = -1, NONE2, SAND_SHORE, SAND_MESAS, DIRT_BIRCHES, DIRT_HILLS, DIRT_PINES, GRASS_HILLS,
GRASS_PINES, LAVA, MAGIC_PLAINS, SNOW_MOUNTAINS, SNOW_TREES, SUBTERRANEAN, SWAMP_TREES, FIERY_FIELDS,
ROCKLANDS, MAGIC_CLOUDS, LUCID_POOLS, HOLY_GROUND, CLOVER_FIELD, EVIL_FOG, FAVORABLE_WINDS, CURSED_GROUND,
ROUGH, SHIP_TO_SHIP, SHIP
};*/
BattleField(const std::string & type = "") : name(type)
{}
static const BattleField NONE;
DLL_LINKAGE friend bool operator==(const BattleField & l, const BattleField & r);
DLL_LINKAGE friend bool operator!=(const BattleField & l, const BattleField & r);
DLL_LINKAGE friend bool operator<(const BattleField & l, const BattleField & r);
operator std::string() const;
int hash() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name;
}
bool isSpecial() const
{
return name.find('_') >= 0; // hack for special battlefields, move to JSON
}
protected:
std::string name;
};
class DLL_LINKAGE Terrain
{
@ -77,7 +39,7 @@ public:
std::string terrainViewPatterns;
int horseSoundId;
Type type;
std::vector<BattleField> battleFields;
std::vector<std::string> battleFields;
};
class DLL_LINKAGE Manager

View File

@ -32,6 +32,7 @@
#include "rmg/CRmgTemplateStorage.h"
#include "mapping/CMapEditManager.h"
#include "ScriptHandler.h"
#include "BattleFieldHandler.h"
LibClasses * VLC = nullptr;
@ -110,6 +111,11 @@ spells::effects::Registry * LibClasses::spellEffects()
return spells::effects::GlobalRegistry::get();
}
const BattleFieldService * LibClasses::battlefields() const
{
return battlefieldsHandler;
}
void LibClasses::updateEntity(Metatype metatype, int32_t index, const JsonNode & data)
{
switch(metatype)
@ -205,6 +211,8 @@ void LibClasses::init(bool onlyEssential)
createHandler(scriptHandler, "Script", pomtime);
createHandler(battlefieldsHandler, "Battlefields", pomtime);
logGlobal->info("\tInitializing handlers: %d ms", totalTime.getDiff());
modh->load();
@ -231,6 +239,7 @@ void LibClasses::clear()
delete tplh;
delete terviewh;
delete scriptHandler;
delete battlefieldsHandler;
makeNull();
}
@ -250,6 +259,7 @@ void LibClasses::makeNull()
tplh = nullptr;
terviewh = nullptr;
scriptHandler = nullptr;
battlefieldsHandler = nullptr;
}
LibClasses::LibClasses()

View File

@ -24,6 +24,7 @@ class CTownHandler;
class CGeneralTextHandler;
class CModHandler;
class CContentHandler;
class BattleFieldHandler;
class IBonusTypeHandler;
class CBonusTypeHandler;
class CTerrainViewPatternConfig;
@ -56,6 +57,7 @@ public:
const scripting::Service * scripts() const override;
const spells::Service * spells() const override;
const SkillService * skills() const override;
const BattleFieldService * battlefields() const override;
void updateEntity(Metatype metatype, int32_t index, const JsonNode & data) override;
@ -76,6 +78,7 @@ public:
CModHandler * modh;
CTerrainViewPatternConfig * terviewh;
CRmgTemplateStorage * tplh;
BattleFieldHandler * battlefieldsHandler;
scripting::ScriptHandler * scriptHandler;
LibClasses(); //c-tor, loads .lods and NULLs handlers
@ -104,6 +107,8 @@ public:
h & objtypeh;
h & spellh;
h & skillh;
h & battlefieldsHandler;
if(!h.saving)
{
//modh will be changed and modh->content will be empty after deserialization

View File

@ -16,6 +16,7 @@
#include "../mapObjects/CGTownInstance.h"
#include "../CGeneralTextHandler.h"
#include "../Terrain.h"
#include "../BattleFieldHandler.h"
//TODO: remove
#include "../IGameCallback.h"
@ -458,64 +459,12 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, const Terrain & terrain,
auto good = std::make_shared<CreatureAlignmentLimiter>(EAlignment::GOOD);
auto evil = std::make_shared<CreatureAlignmentLimiter>(EAlignment::EVIL);
//giving terrain overlay premies
int bonusSubtype = -1;
auto bgInfo = VLC->battlefields()->getById(battlefieldType);
if(battlefieldType == BattleField("magic_plains"))
for(const std::shared_ptr<Bonus> & bonus : bgInfo->bonuses)
{
bonusSubtype = 0;
curB->addNewBonus(bonus);
}
if(battlefieldType == BattleField("fiery_fields"))
{
if(bonusSubtype == -1) bonusSubtype = 2;
}
if(battlefieldType == BattleField("rocklands"))
{
if(bonusSubtype == -1) bonusSubtype = 8;
}
if(battlefieldType == BattleField("magic_clouds"))
{
if(bonusSubtype == -1) bonusSubtype = 1;
}
if(battlefieldType == BattleField("lucid_pools"))
{
if(bonusSubtype == -1) bonusSubtype = 4;
}
if(bonusSubtype != -1)
{ //common part for cases 9, 14, 15, 16, 17
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL,Bonus::TERRAIN_OVERLAY, 3, battlefieldType.hash(), bonusSubtype));
}
else if(battlefieldType == BattleField("holy_ground"))
{
std::string goodArmyDesc = VLC->generaltexth->arraytxt[123];
goodArmyDesc.erase(goodArmyDesc.size() - 2, 2); //omitting hardcoded +1 in description
std::string evilArmyDesc = VLC->generaltexth->arraytxt[124];
evilArmyDesc.erase(evilArmyDesc.size() - 2, 2);
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, +1, battlefieldType.hash(), goodArmyDesc, 0)->addLimiter(good));
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, -1, battlefieldType.hash(), evilArmyDesc, 0)->addLimiter(evil));
}
else if(battlefieldType == BattleField("clover_field"))
{ //+2 luck bonus for neutral creatures
std::string desc = VLC->generaltexth->arraytxt[83];
desc.erase(desc.size() - 2, 2);
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::LUCK, Bonus::TERRAIN_OVERLAY, +2, battlefieldType.hash(), desc, 0)->addLimiter(neutral));
}
else if(battlefieldType == BattleField("evil_fog"))
{
std::string goodArmyDesc = VLC->generaltexth->arraytxt[126];
goodArmyDesc.erase(goodArmyDesc.size() - 2, 2);
std::string evilArmyDesc = VLC->generaltexth->arraytxt[125];
evilArmyDesc.erase(evilArmyDesc.size() - 2, 2);
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, -1, battlefieldType.hash(), goodArmyDesc, 0)->addLimiter(good));
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::MORALE, Bonus::TERRAIN_OVERLAY, +1, battlefieldType.hash(), evilArmyDesc, 0)->addLimiter(evil));
}
else if(battlefieldType == BattleField("cursed_ground"))
{
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::NO_MORALE, Bonus::TERRAIN_OVERLAY, 0, battlefieldType.hash(), VLC->generaltexth->arraytxt[112], 0));
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::NO_LUCK, Bonus::TERRAIN_OVERLAY, 0, battlefieldType.hash(), VLC->generaltexth->arraytxt[81], 0));
curB->addNewBonus(std::make_shared<Bonus>(Bonus::ONE_BATTLE, Bonus::BLOCK_MAGIC_ABOVE, Bonus::TERRAIN_OVERLAY, 1, battlefieldType.hash(), 0, Bonus::INDEPENDENT_MIN));
}
//overlay premies given
//native terrain bonuses
static auto nativeTerrain = std::make_shared<CreatureTerrainLimiter>();

View File

@ -17,6 +17,7 @@
#include "../NetPacks.h"
#include "../spells/CSpellHandler.h"
#include "../mapObjects/CGTownInstance.h"
#include "../BattleFieldHandler.h"
namespace SiegeStuffThatShouldBeMovedToHandlers // <=== TODO
{
@ -1058,24 +1059,15 @@ AccessibilityInfo CBattleInfoCallback::getAccesibility() const
}
//special battlefields with logically unavailable tiles
std::vector<BattleHex> impassableHexes;
if(battleGetBattlefieldType() == BattleField("ship_to_ship"))
auto bFieldType = battleGetBattlefieldType();
if(bFieldType != BattleField::NONE)
{
impassableHexes =
{
6, 7, 8, 9,
24, 25, 26,
58, 59, 60,
75, 76, 77,
92, 93, 94,
109, 110, 111,
126, 127, 128,
159, 160, 161, 162, 163,
176, 177, 178, 179, 180
};
std::vector<BattleHex> impassableHexes = bFieldType.getInfo()->impassableHexes;
for(auto hex : impassableHexes)
ret[hex] = EAccessibility::UNAVAILABLE;
}
for(auto hex : impassableHexes)
ret[hex] = EAccessibility::UNAVAILABLE;
//gate -> should be before stacks
if(battleGetSiegeLevel() > 0)

View File

@ -515,10 +515,10 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin
else
aiValue = static_cast<boost::optional<si32>>(input["aiValue"].Integer());
if(input["battleground"].isNull())
battlefield = BattleField::NONE;
if(input["battleground"].getType() == JsonNode::JsonType::DATA_STRING)
battlefield = input["battleground"].String();
else
battlefield = BattleField(input["battleground"].String());
battlefield = boost::none;
initTypeData(input);
}
@ -577,7 +577,7 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const
BattleField AObjectTypeHandler::getBattlefield() const
{
return battlefield;
return battlefield ? BattleField::fromString(battlefield.get()) : BattleField::NONE;
}
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & terrainType) const

View File

@ -150,7 +150,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable
boost::optional<si32> aiValue;
BattleField battlefield;
boost::optional<std::string> battlefield;
protected:
void preInitObject(CGObjectInstance * obj) const;
@ -219,6 +219,7 @@ public:
h & subTypeName;
h & sounds;
h & aiValue;
h & battlefield;
}
};

View File

@ -461,12 +461,15 @@ const std::vector<CTerrainViewPatternConfig::TVPVector> & CTerrainViewPatternCon
return iter->second;
}
boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getTerrainViewPatternById(const Terrain & terrain, const std::string & id) const
boost::optional<const TerrainViewPattern &> CTerrainViewPatternConfig::getTerrainViewPatternById(std::string patternId, const std::string & id) const
{
const std::vector<TVPVector> & groupPatterns = getTerrainViewPatterns(terrain);
auto iter = terrainViewPatterns.find(patternId);
const std::vector<TVPVector> & groupPatterns = (iter == terrainViewPatterns.end()) ? terrainViewPatterns.at("normal") : iter->second;
for (const TVPVector & patternFlips : groupPatterns)
{
const TerrainViewPattern & pattern = patternFlips.front();
if(id == pattern.id)
{
return boost::optional<const TerrainViewPattern &>(pattern);

View File

@ -327,7 +327,7 @@ public:
~CTerrainViewPatternConfig();
const std::vector<TVPVector> & getTerrainViewPatterns(const Terrain & terrain) const;
boost::optional<const TerrainViewPattern &> getTerrainViewPatternById(const Terrain & terrain, const std::string & id) const;
boost::optional<const TerrainViewPattern &> getTerrainViewPatternById(std::string patternId, const std::string & id) const;
boost::optional<const TVPVector &> getTerrainViewPatternsById(const Terrain & terrain, const std::string & id) const;
const TVPVector * getTerrainTypePatternById(const std::string & id) const;
void flipPattern(TerrainViewPattern & pattern, int flip) const;

View File

@ -55,6 +55,7 @@ void registerTypesMapObjects1(Serializer &s)
s.template registerType<CGObjectInstance, CGShipyard>(); s.template registerType<IShipyard, CGShipyard>();
s.template registerType<CGObjectInstance, CGDenOfthieves>();
s.template registerType<CGObjectInstance, CGLighthouse>();
s.template registerType<CGObjectInstance, CGTerrainPatch>();
s.template registerType<CGObjectInstance, CGMarket>(); s.template registerType<IMarket, CGMarket>();
s.template registerType<CGMarket, CGBlackMarket>();
s.template registerType<CGMarket, CGUniversity>();
@ -108,6 +109,7 @@ void registerTypesMapObjectTypes(Serializer &s)
REGISTER_GENERIC_HANDLER(CGHeroInstance);
REGISTER_GENERIC_HANDLER(CGKeymasterTent);
REGISTER_GENERIC_HANDLER(CGLighthouse);
REGISTER_GENERIC_HANDLER(CGTerrainPatch);
REGISTER_GENERIC_HANDLER(CGMagi);
REGISTER_GENERIC_HANDLER(CGMagicSpring);
REGISTER_GENERIC_HANDLER(CGMagicWell);

View File

@ -246,8 +246,18 @@ void CMapGenOptions::finalize(CRandomGenerator & rand)
if(waterContent == EWaterContent::RANDOM)
{
waterContent = *RandomGeneratorUtil::nextItem(mapTemplate->getWaterContentAllowed(), rand);
auto allowedContent = mapTemplate->getWaterContentAllowed();
if(allowedContent.size())
{
waterContent = *RandomGeneratorUtil::nextItem(mapTemplate->getWaterContentAllowed(), rand);
}
else
{
waterContent = EWaterContent::NONE;
}
}
if(monsterStrength == EMonsterStrength::RANDOM)
{
monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(EMonsterStrength::GLOBAL_WEAK, EMonsterStrength::GLOBAL_STRONG));

View File

@ -2019,6 +2019,10 @@ int3 CRmgTemplateZone::makeBoat(TRmgTemplateZoneId land, const std::set<int3> &
{
std::set<int3> lakeCoast;
std::set_intersection(gen->getZones()[land]->getCoastTiles().begin(), gen->getZones()[land]->getCoastTiles().end(), lake.begin(), lake.end(), std::inserter(lakeCoast, lakeCoast.begin()));
if(lakeCoast.empty())
return int3(-1, -1, -1);
for(int randomAttempts = 0; randomAttempts<5; ++randomAttempts)
{
auto coastTile = *RandomGeneratorUtil::nextItem(lakeCoast, gen->rand);

View File

@ -12,6 +12,7 @@
#include "ISpellMechanics.h"
#include "../CRandomGenerator.h"
#include "../VCMI_Lib.h"
#include "../HeroBonus.h"
#include "../battle/CBattleInfoCallback.h"
@ -39,6 +40,7 @@
#include "../CHeroHandler.h"//todo: remove
#include "../IGameCallback.h"//todo: remove
#include "../BattleFieldHandler.h"
namespace spells
{
@ -520,7 +522,7 @@ bool BaseMechanics::adaptProblem(ESpellCastProblem::ESpellCastProblem source, Pr
caster->getCasterName(text);
target.add(std::move(text), spells::Problem::NORMAL);
}
else if(b && b->source == Bonus::TERRAIN_OVERLAY && b->sid == BattleField("cursed_ground").hash())
else if(b && b->source == Bonus::TERRAIN_OVERLAY && VLC->battlefields()->getByIndex(b->sid)->identifier == "cursed_ground")
{
text.addTxt(MetaString::GENERAL_TXT, 537);
target.add(std::move(text), spells::Problem::NORMAL);

View File

@ -10,12 +10,14 @@
#include "StdInc.h"
#include "BattleCb.h"
#include <vcmi/Entity.h>
#include "../LuaStack.h"
#include "../LuaCallWrapper.h"
#include "../../../lib/GameConstants.h"
#include "../../../lib/battle/Unit.h"
#include "../../../lib/BattleFieldHandler.h"
namespace scripting
{
@ -73,7 +75,7 @@ int BattleCbProxy::getBattlefieldType(lua_State * L)
auto ret = object->battleGetBattlefieldType();
return LuaStack::quickRetStr(L, ret);
return LuaStack::quickRetStr(L, ret.getInfo()->identifier);
}
int BattleCbProxy::getTerrainType(lua_State * L)

View File

@ -55,16 +55,16 @@ end
local SPECIAL_FIELDS = {}
SPECIAL_FIELDS[0] = 0
SPECIAL_FIELDS[22] = 1
SPECIAL_FIELDS[9] = 2
SPECIAL_FIELDS[18] = 3
SPECIAL_FIELDS[20] = 4
SPECIAL_FIELDS[19] = 5
SPECIAL_FIELDS[17] = 6
SPECIAL_FIELDS[14] = 7
SPECIAL_FIELDS[15] = 8
SPECIAL_FIELDS[16] = 9
SPECIAL_FIELDS['sand_shore'] = 0
SPECIAL_FIELDS['cursed_ground'] = 1
SPECIAL_FIELDS['magic_plains'] = 2
SPECIAL_FIELDS['holy_ground'] = 3
SPECIAL_FIELDS['evil_fog'] = 4
SPECIAL_FIELDS['clover_field'] = 5
SPECIAL_FIELDS['lucid_pools'] = 6
SPECIAL_FIELDS['fiery_fields'] = 7
SPECIAL_FIELDS['rocklands'] = 8
SPECIAL_FIELDS['magic_clouds'] = 9
function BU:G(x, p1)

View File

@ -2221,7 +2221,7 @@ void CGameHandler::setupBattle(int3 tile, const CArmedInstance *armies[2], const
BattleField terType = gs->battleGetBattlefieldType(tile, getRandomGenerator());
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
terType = BattleField("ship_to_ship");
terType = BattleField::fromString("ship_to_ship");
//send info about battles
BattleStart bs;

View File

@ -10,6 +10,7 @@
#include "StdInc.h"
#include "../../lib/battle/CBattleInfoCallback.h"
#include "../../lib/battle/CUnitState.h"
#include <vstd/RNG.h>
@ -25,7 +26,15 @@ using namespace testing;
class UnitFake : public UnitMock
{
private:
std::shared_ptr<CUnitState> state;
public:
UnitFake()
{
state.reset(new CUnitStateDetached(this, this));
}
void addNewBonus(const std::shared_ptr<Bonus> & b)
{
bonusFake.addNewBonus(b);
@ -58,6 +67,13 @@ public:
EXPECT_CALL(*this, unitSlot()).WillRepeatedly(Return(SlotID(0)));
EXPECT_CALL(*this, creatureIndex()).WillRepeatedly(Return(0));
}
void setDefaultState()
{
EXPECT_CALL(*this, isClone()).WillRepeatedly(Return(false));
EXPECT_CALL(*this, isCaster()).WillRepeatedly(Return(false));
EXPECT_CALL(*this, acquireState()).WillRepeatedly(Return(state));
}
private:
BonusBearerMock bonusFake;
};
@ -207,6 +223,7 @@ TEST_F(BattleFinishedTest, LastAliveUnitWins)
{
UnitFake & unit = unitsFake.add(1);
unit.makeAlive();
unit.setDefaultState();
setDefaultExpectations();
startBattle();
@ -232,6 +249,7 @@ TEST_F(BattleFinishedTest, LastWarMachineNotWins)
UnitFake & unit = unitsFake.add(0);
unit.makeAlive();
unit.makeWarMachine();
unit.setDefaultState();
setDefaultExpectations();
startBattle();
@ -241,17 +259,26 @@ TEST_F(BattleFinishedTest, LastWarMachineNotWins)
TEST_F(BattleFinishedTest, LastWarMachineLoose)
{
UnitFake & unit1 = unitsFake.add(0);
unit1.makeAlive();
try
{
UnitFake & unit1 = unitsFake.add(0);
unit1.makeAlive();
unit1.setDefaultState();
UnitFake & unit2 = unitsFake.add(1);
unit2.makeAlive();
unit2.makeWarMachine();
UnitFake & unit2 = unitsFake.add(1);
unit2.makeAlive();
unit2.makeWarMachine();
unit2.setDefaultState();
setDefaultExpectations();
startBattle();
setDefaultExpectations();
startBattle();
expectBattleWinner(0);
expectBattleWinner(0);
}
catch(std::exception e)
{
logGlobal->error(e.what());
}
}
class BattleMatchOwnerTest : public CBattleInfoCallbackTest

View File

@ -155,7 +155,7 @@ TEST_F(ERM_BU_G, Get)
source << "!?PI;" << std::endl;
source << "!!BU:G?v1;" << std::endl;
EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BattleField("snow_trees")));
EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BattleField::fromString("snow_trees")));
loadScript(VLC->scriptHandler->erm, source.str());
@ -169,12 +169,14 @@ TEST_F(ERM_BU_G, Get)
TEST_F(ERM_BU_G, Get2)
{
const int EXPECTED_ERM_FOG_CODE = 4;
std::stringstream source;
source << "VERM" << std::endl;
source << "!?PI;" << std::endl;
source << "!!BU:G?v1;" << std::endl;
EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BattleField("evil_fog")));
EXPECT_CALL(binfoMock, battleGetBattlefieldType()).WillOnce(Return(BattleField::fromString("evil_fog")));
loadScript(VLC->scriptHandler->erm, source.str());
runServer();
@ -182,7 +184,7 @@ TEST_F(ERM_BU_G, Get2)
JsonNode actualState = context->saveState();
EXPECT_EQ(actualState["ERM"]["v"]["1"], JsonUtils::floatNode(4)) << actualState.toJson(true);
EXPECT_EQ(actualState["ERM"]["v"]["1"], JsonUtils::floatNode(EXPECTED_ERM_FOG_CODE)) << actualState.toJson(true);
}
//TODO: ERM_BU_G Set

View File

@ -194,7 +194,7 @@ public:
const auto t = gameCallback->getTile(tile);
Terrain terrain = t->terType;
BattleField terType = BattleField("grass_hills");
BattleField terType = BattleField::fromString("grass_hills");
//send info about battles

View File

@ -132,7 +132,7 @@ TEST(MapManager, DrawTerrain_View)
const auto & id = patternParts[1];
// Get mapping range
const auto & pattern = VLC->terviewh->getTerrainViewPatternById(groupStr, id);
const auto & pattern = VLC->terviewh->getTerrainViewPatternById(groupStr, id);
const auto & mapping = (*pattern).mapping;
const auto & positionsNode = node["pos"].Vector();

View File

@ -23,6 +23,7 @@
#include "MapComparer.h"
#include "../JsonComparer.h"
#include "mock/ZoneOptionsFake.h"
static const int TEST_RANDOM_SEED = 1337;
@ -43,10 +44,12 @@ TEST(MapFormat, Random)
CMapGenOptions opt;
CRmgTemplate tmpl;
std::shared_ptr<ZoneOptionsFake> zoneOptions = std::make_shared<ZoneOptionsFake>();
const_cast<CRmgTemplate::CPlayerCountRange &>(tmpl.getCpuPlayers()).addRange(1, 4);
const_cast<CRmgTemplate::Zones &>(tmpl.getZones())[0] = std::make_shared<rmg::ZoneOptions>();
const_cast<CRmgTemplate::Zones &>(tmpl.getZones())[0] = zoneOptions;
zoneOptions->setOwner(1);
opt.setMapTemplate(&tmpl);
opt.setHeight(CMapHeader::MAP_SIZE_MIDDLE);

View File

@ -92,7 +92,7 @@ void BattleFake::setupEmptyBattlefield()
{
EXPECT_CALL(*this, getDefendedTown()).WillRepeatedly(Return(nullptr));
EXPECT_CALL(*this, getAllObstacles()).WillRepeatedly(Return(IBattleInfo::ObstacleCList()));
EXPECT_CALL(*this, getBattlefieldType()).WillRepeatedly(Return(BattleField::NONE));
EXPECT_CALL(*this, getBattlefieldType()).WillRepeatedly(Return(BattleField::fromString("grass_hills")));
}

View File

@ -0,0 +1,23 @@
/*
* BattleFake.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
*
*/
#include "../../../lib/mapping/CMap.h"
#include "../../../lib/rmg/CMapGenOptions.h"
#include "../../../lib/rmg/CMapGenerator.h"
#pragma once
class ZoneOptionsFake : public rmg::ZoneOptions
{
public:
void setOwner(int ow)
{
this->owner = ow;
}
};

View File

@ -23,7 +23,8 @@ public:
MOCK_CONST_METHOD0(heroTypes, const HeroTypeService *());
MOCK_CONST_METHOD0(scripts, const scripting::Service *());
MOCK_CONST_METHOD0(spells, const spells::Service *());
MOCK_CONST_METHOD0(skills, const SkillService *());
MOCK_CONST_METHOD0(skills, const SkillService * ());
MOCK_CONST_METHOD0(battlefields, const BattleFieldService *());
MOCK_METHOD3(updateEntity, void(Metatype, int32_t, const JsonNode &));

View File

@ -232,7 +232,7 @@ TEST_F(CloneApplyTest, SetsLifetimeMarker)
{
setDefaultExpectations();
EXPECT_CALL(*battleFake, addUnitBonus(_,_)).WillOnce(Invoke(this, &CloneApplyTest::checkCloneLifetimeMarker));
EXPECT_CALL(*battleFake, addUnitBonus(_, _)).WillOnce(Invoke(this, &CloneApplyTest::checkCloneLifetimeMarker));
subject->apply(&serverMock, &mechanicsMock, target);
}