1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Merge branch 'develop' into SDL2

This commit is contained in:
AlexVinS 2014-06-24 14:09:44 +04:00
commit 3b8d0e44d4
150 changed files with 18844 additions and 15156 deletions

View File

@ -3,9 +3,9 @@
#include "VCAI.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CHeroHandler.h"
#include "../../lib/mapObjects/CBank.h"
/*
* AIUtility.cpp, part of VCMI engine
@ -303,11 +303,11 @@ ui64 evaluateDanger(const CGObjectInstance *obj)
case Obj::SHIPWRECK: //shipwreck
case Obj::DERELICT_SHIP: //derelict ship
// case Obj::PYRAMID:
return fh->estimateBankDanger (VLC->objh->bankObjToIndex(obj));
return fh->estimateBankDanger (dynamic_cast<const CBank *>(obj));
case Obj::PYRAMID:
{
if(obj->subID == 0)
return fh->estimateBankDanger (VLC->objh->bankObjToIndex(obj));
return fh->estimateBankDanger (dynamic_cast<const CBank *>(obj));
else
return 0;
}
@ -377,7 +377,7 @@ int3 whereToExplore(HeroPtr h)
}
}
}
removeDuplicates (nearbyVisitableObjs); //one object may occupy multiple tiles
vstd::removeDuplicates (nearbyVisitableObjs); //one object may occupy multiple tiles
boost::sort(nearbyVisitableObjs, isCloser);
if(nearbyVisitableObjs.size())
return nearbyVisitableObjs.back()->visitablePos();

View File

@ -5,7 +5,6 @@
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/Connection.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"
@ -135,44 +134,6 @@ bool objWithID(const CGObjectInstance *obj)
return obj->ID == id;
}
template <typename Container, typename Item>
bool erase_if_present(Container &c, const Item &item)
{
auto i = std::find(c.begin(), c.end(), item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename V, typename Item, typename Item2>
bool erase_if_present(std::map<Item,V> & c, const Item2 &item)
{
auto i = c.find(item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename Container, typename Pred>
void erase(Container &c, Pred pred)
{
c.erase(boost::remove_if(c, pred), c.end());
}
template<typename T>
void removeDuplicates(std::vector<T> &vec)
{
boost::sort(vec);
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
std::string strFromInt3(int3 pos);
void foreach_tile_pos(std::function<void(const int3& pos)> foo);
void foreach_tile_pos(CCallback * cbp, std::function<void(CCallback * cbp, const int3& pos)> foo); // avoid costly retrieval of thread-specific pointer
@ -200,4 +161,4 @@ bool compareMovement(HeroPtr lhs, HeroPtr rhs);
bool compareHeroStrength(HeroPtr h1, HeroPtr h2);
bool compareArmyStrength(const CArmedInstance *a1, const CArmedInstance *a2);
ui64 howManyReinforcementsCanGet(HeroPtr h, const CGTownInstance *t);
int3 whereToExplore(HeroPtr h);
int3 whereToExplore(HeroPtr h);

View File

@ -2,11 +2,11 @@
#include "Fuzzy.h"
#include <limits>
#include "../../lib/CObjectHandler.h"
#include "../../lib/mapObjects/MapObjects.h"
#include "../../lib/mapObjects/CommonConstructors.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/VCMI_Lib.h"
#include "../../CCallback.h"
//#include "Goals.cpp"
#include "VCAI.h"
/*
@ -42,16 +42,6 @@ struct armyStructure
ui32 maxSpeed;
};
ui64 evaluateBankConfig (BankConfig * bc)
{
ui64 danger = 0;
for (auto opt : bc->guards)
{
danger += VLC->creh->creatures[opt.first]->fightValue * opt.second;
}
return danger;
}
armyStructure evaluateArmyStructure (const CArmedInstance * army)
{
ui64 totalStrenght = army->getArmyStrength();
@ -209,42 +199,26 @@ void FuzzyHelper::initTacticalAdvantage()
}
}
ui64 FuzzyHelper::estimateBankDanger (int ID)
ui64 FuzzyHelper::estimateBankDanger (const CBank * bank)
{
std::vector <ConstTransitivePtr<BankConfig>> & configs = VLC->objh->banksInfo[ID];
auto info = VLC->objtypeh->getHandlerFor(bank->ID, bank->subID)->getObjectInfo(bank->appearance);
ui64 val = std::numeric_limits<ui64>::max();
try
{
switch (configs.size())
{
case 4:
try
{
for (int i = 0; i < 4; ++i)
{
int bankVal = evaluateBankConfig (VLC->objh->banksInfo[ID][i]);
bankDanger->term("Bank" + boost::lexical_cast<std::string>(i))->setMinimum(bankVal * 0.5f);
bankDanger->term("Bank" + boost::lexical_cast<std::string>(i))->setMaximum(bankVal * 1.5f);
}
//comparison purposes
//int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5;
//dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(0.5);
bankInput->setInput (0.5);
engine.process (BANK_DANGER);
//engine.process();
val = bankDanger->output().defuzzify(); //some expected value of this bank
}
catch (fl::FuzzyException & fe)
{
logAi->errorStream() << fe.name() << ": " << fe.message();
}
break;
case 1: //rare case - Pyramid
val = evaluateBankConfig (VLC->objh->banksInfo[ID][0]);
break;
default:
logAi->warnStream() << ("Uhnandled bank config!");
}
bankDanger->term("Bank0")->setMinimum(info->minGuards().totalStrength * 0.5f);
bankDanger->term("Bank0")->setMaximum(info->minGuards().totalStrength * 1.5f);
bankDanger->term("Bank1")->setMinimum(info->maxGuards().totalStrength * 0.5f);
bankDanger->term("Bank1")->setMaximum(info->maxGuards().totalStrength * 1.5f);
//comparison purposes
//int averageValue = (evaluateBankConfig (VLC->objh->banksInfo[ID][0]) + evaluateBankConfig (VLC->objh->banksInfo[ID][3])) * 0.5;
//dynamic_cast<fl::SingletonTerm*>(bankInput->term("SET"))->setValue(0.5);
bankInput->setInput (0.5);
engine.process (BANK_DANGER);
//engine.process();
val = bankDanger->output().defuzzify(); //some expected value of this bank
}
catch (fl::FuzzyException & fe)
{

View File

@ -14,6 +14,7 @@
class VCAI;
class CArmedInstance;
class CBank;
class FuzzyHelper
{
@ -72,7 +73,7 @@ public:
float evaluate (Goals::AbstractGoal & g);
void setPriority (Goals::TSubgoal & g);
ui64 estimateBankDanger (int ID);
ui64 estimateBankDanger (const CBank * bank);
float getTacticalAdvantage (const CArmedInstance *we, const CArmedInstance *enemy); //returns factor how many times enemy is stronger than us
Goals::TSubgoal chooseSolution (Goals::TGoalVec vec);

View File

@ -1,7 +1,6 @@
#pragma once
#include "../../lib/VCMI_Lib.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/CBuildingHandler.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CTownHandler.h"

View File

@ -2,7 +2,7 @@
#include "VCAI.h"
#include "Goals.h"
#include "../../lib/UnlockGuard.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/mapObjects/MapObjects.h"
#include "../../lib/CConfigHandler.h"
#include "../../lib/CHeroHandler.h"

View File

@ -4,7 +4,6 @@
#include "Goals.h"
#include "../../lib/AI_Base.h"
#include "../../CCallback.h"
#include "../../lib/CDefObjInfoHandler.h"
#include "../../lib/CThreadHelper.h"
@ -14,7 +13,6 @@
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/Connection.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"

View File

@ -9,10 +9,9 @@
#include "client/Client.h"
#include "lib/mapping/CMap.h"
#include "lib/CBuildingHandler.h"
#include "lib/CDefObjInfoHandler.h"
#include "lib/mapObjects/CObjectClassesHandler.h"
#include "lib/CGeneralTextHandler.h"
#include "lib/CHeroHandler.h"
#include "lib/CObjectHandler.h"
#include "lib/Connection.h"
#include "lib/NetPacks.h"
#include "client/mapHandler.h"

View File

@ -117,9 +117,14 @@ endif()
if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) #so far all *nix compilers support such parameters
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CLANG_SPECIFIC_FLAGS "-Wno-mismatched-tags")
set(CLANG_SPECIFIC_FLAGS "-Wno-mismatched-tags")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -Wpointer-arith -Wno-switch -Wno-sign-compare -Wno-unused-parameter -Wuninitialized -Wno-overloaded-virtual ${CLANG_SPECIFIC_FLAGS}")
if(UNIX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden")
endif()
endif()
if(WIN32) # on Win everything goes into H3 root directory

View File

@ -608,6 +608,44 @@ namespace vstd
return defaultValue;
}
template <typename Container, typename Item>
bool erase_if_present(Container &c, const Item &item)
{
auto i = std::find(c.begin(), c.end(), item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename V, typename Item, typename Item2>
bool erase_if_present(std::map<Item,V> & c, const Item2 &item)
{
auto i = c.find(item);
if (i != c.end())
{
c.erase(i);
return true;
}
return false;
}
template <typename Container, typename Pred>
void erase(Container &c, Pred pred)
{
c.erase(boost::remove_if(c, pred), c.end());
}
template<typename T>
void removeDuplicates(std::vector<T> &vec)
{
boost::sort(vec);
vec.erase(std::unique(vec.begin(), vec.end()), vec.end());
}
using boost::math::round;
}
using vstd::operator-=;

View File

@ -6,7 +6,7 @@
#include "../lib/filesystem/Filesystem.h"
#include "../lib/mapping/CMap.h"
#include "../lib/CModHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/CGameState.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h"

View File

@ -17,7 +17,7 @@
#include "CDefHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/CTownHandler.h"
#include "../lib/mapping/CMap.h"
#include "../lib/JsonNode.h"
@ -25,7 +25,7 @@
#include "CPreGame.h"
#include "../lib/VCMI_Lib.h"
#include "../lib/CSpellHandler.h"
#include "CSoundBase.h"
#include "../lib/CSoundBase.h"
#include "../lib/CGameState.h"
#include "CMusicHandler.h"
#include "gui/CGuiHandler.h"

View File

@ -7,7 +7,7 @@
#include "../lib/CCreatureHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CModHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CTownHandler.h"
#include "CAdvmapInterface.h"

View File

@ -31,5 +31,5 @@ void CGameInfo::setFromLib()
heroh = VLC->heroh;
objh = VLC->objh;
spellh = VLC->spellh;
dobjinfo = VLC->dobjinfo;
objtypeh = VLC->objtypeh;
}

View File

@ -23,7 +23,7 @@ class CBuildingHandler;
class CObjectHandler;
class CSoundHandler;
class CMusicHandler;
class CDefObjInfoHandler;
class CObjectClassesHandler;
class CTownHandler;
class CGeneralTextHandler;
class CConsoleHandler;
@ -57,11 +57,10 @@ public:
ConstTransitivePtr<CCreatureHandler> creh;
ConstTransitivePtr<CSpellHandler> spellh;
ConstTransitivePtr<CObjectHandler> objh;
ConstTransitivePtr<CDefObjInfoHandler> dobjinfo;
ConstTransitivePtr<CObjectClassesHandler> objtypeh;
CGeneralTextHandler * generaltexth;
CMapHandler * mh;
CTownHandler * townh;
//CTownHandler * townh;
void setFromLib();

View File

@ -20,7 +20,7 @@
#include "CDefHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/NetPacksBase.h"
#include "gui/CGuiHandler.h"

View File

@ -4,8 +4,6 @@
#include "gui/CIntObjectClasses.h"
#include "GUIClasses.h"
//#include "CPlayerInterface.h"
/*
* CHeroWindow.h, part of VCMI engine
*

View File

@ -5,7 +5,7 @@
#include "../lib/CCreatureHandler.h" //creatures name for objects list
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CModHandler.h" //for buildings per turn
#include "../lib/CObjectHandler.h" //Hero/Town objects
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/CHeroHandler.h" // only for calculating required xp? worth it?
#include "../lib/CTownHandler.h"
#include "CAnimation.h" //CAnimImage
@ -500,7 +500,7 @@ void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInst
OwnedObjectInfo &info = visibleObjects[object->subID];
if (info.count++ == 0)
{
info.hoverText = CGI->creh->creatures[CGI->objh->cregens.find(object->subID)->second]->namePl;
info.hoverText = object->getHoverText();
info.imageID = object->subID;
}
}
@ -953,4 +953,4 @@ void CHeroItem::onArtChange(int tabIndex)
//redraw item after background change
if (active)
redraw();
}
}

View File

@ -34,7 +34,6 @@
#include "CMessage.h"
#include "../lib/CModHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CArtHandler.h"
#include "../lib/CScriptingModule.h"
#include "../lib/GameConstants.h"
@ -44,7 +43,6 @@
#ifdef _WIN32
#include "SDL_syswm.h"
#endif
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/UnlockGuard.h"
#include "CMT.h"

View File

@ -48,8 +48,6 @@ set(client_SRCS
)
set(client_HEADERS
CSoundBase.h
gui/SDL_Pixels.h
)

View File

@ -2,9 +2,9 @@
#include <SDL_mixer.h>
#include "CMusicHandler.h"
#include "CGameInfo.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/CSpellHandler.h"
#include "../client/CGameInfo.h"
#include "../lib/JsonNode.h"
#include "../lib/GameConstants.h"
#include "../lib/filesystem/Filesystem.h"

View File

@ -1,7 +1,7 @@
#pragma once
#include "../lib/CConfigHandler.h"
#include "CSoundBase.h"
#include "../lib/CSoundBase.h"
#include "../lib/CCreatureHandler.h"
/*

View File

@ -1,5 +1,4 @@
#include "StdInc.h"
#include "../lib/CDefObjInfoHandler.h"
#include "CAdvmapInterface.h"
#include "battle/CBattleInterface.h"
#include "battle/CBattleInterfaceClasses.h"
@ -13,7 +12,6 @@
#include "CQuestLog.h"
#include "CMessage.h"
#include "CPlayerInterface.h"
//#include "gui/SDL_Extensions.h"
#include "gui/SDL_Extensions.h"
#include "../lib/CConfigHandler.h"
#include "battle/CCreatureAnimation.h"
@ -21,7 +19,6 @@
#include "../lib/CArtHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/Connection.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CTownHandler.h"

View File

@ -11,11 +11,9 @@
#include "gui/CCursorHandler.h"
#include "CAnimation.h"
#include "CDefHandler.h"
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/mapping/CCampaignHandler.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/JsonNode.h"
@ -1716,7 +1714,10 @@ CRandomMapTab::CRandomMapTab()
addButtonsWithRandToGroup(monsterStrengthGroup, monsterStrengthBtns, 0, 2, WIDE_BTN_WIDTH, 248, 251);
monsterStrengthGroup->onChange = [&](int btnId)
{
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId));
if (btnId < 0)
mapGenOptions.setMonsterStrength(EMonsterStrength::RANDOM);
else
mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(btnId + EMonsterStrength::GLOBAL_WEAK)); //value 2 to 4
};
// Show random maps btn

View File

@ -16,7 +16,6 @@
#include "../lib/CGameState.h"
#include "../lib/CArtHandler.h"
#include "../lib/NetPacksBase.h"
#include "../lib/CObjectHandler.h"
#include "gui/CGuiHandler.h"
#include "gui/CIntObjectClasses.h"

View File

@ -3,7 +3,6 @@
#include "Graphics.h"
#include "CDefHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "CVideoHandler.h"

View File

@ -11,11 +11,9 @@
#include "../lib/BattleState.h"
#include "../lib/CModHandler.h"
#include "../lib/CArtHandler.h"
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CBuildingHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/Connection.h"

View File

@ -24,7 +24,6 @@
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CModHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CondSh.h"

View File

@ -12,19 +12,17 @@
#include "../CCallback.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CCreatureHandler.h"
#include "CBitmapHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/CGameState.h"
#include "../lib/JsonNode.h"
#include "../lib/vcmi_endian.h"
#include "../lib/GameConstants.h"
#include "../lib/CStopWatch.h"
#include "CAnimation.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
using namespace boost::assign;
using namespace CSDL_Ext;
@ -166,13 +164,11 @@ void Graphics::loadHeroAnims()
for(auto & elem : CGI->heroh->classes.heroClasses)
{
const CHeroClass * hc = elem;
if (!vstd::contains(heroAnims, hc->imageMapFemale))
heroAnims[hc->imageMapFemale] = loadHeroAnim(hc->imageMapFemale, rotations);
if (!vstd::contains(heroAnims, hc->imageMapMale))
heroAnims[hc->imageMapMale] = loadHeroAnim(hc->imageMapMale, rotations);
for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->id)->getTemplates())
{
if (!heroAnims.count(templ.animationFile))
heroAnims[templ.animationFile] = loadHeroAnim(templ.animationFile, rotations);
}
}
boatAnims.push_back(loadHeroAnim("AB01_.DEF", rotations));

View File

@ -9,14 +9,12 @@
#include "CGameInfo.h"
#include "../lib/Connection.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CObjectHandler.h"
#include "../lib/VCMI_Lib.h"
#include "../lib/mapping/CMap.h"
#include "../lib/VCMIDirs.h"
#include "../lib/CSpellHandler.h"
#include "CSoundBase.h"
#include "../lib/CSoundBase.h"
#include "mapHandler.h"
#include "GUIClasses.h"
#include "../lib/CConfigHandler.h"

View File

@ -6,7 +6,6 @@
#include "../CAdvmapInterface.h"
#include "../CAnimation.h"
#include "../CBitmapHandler.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/CHeroHandler.h"
# include "../CDefHandler.h"
#include "../../lib/CSpellHandler.h"

View File

@ -16,7 +16,6 @@
#include "../../lib/CGeneralTextHandler.h"
#include "../../lib/NetPacks.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CObjectHandler.h"
#include "../../lib/BattleState.h"
#include "../CMusicHandler.h"
#include "../CVideoHandler.h"

View File

@ -1,7 +1,6 @@
#pragma once
#include "../../lib/FunctionList.h"
//#include "../CDefHandler.h"
#include "../CAnimation.h"
/*

View File

@ -14,12 +14,12 @@
#include "CBitmapHandler.h"
#include "gui/SDL_Extensions.h"
#include "CGameInfo.h"
#include "../lib/CDefObjInfoHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/CGameState.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h"
#include "Graphics.h"
#include "../lib/CObjectHandler.h"
#include "../lib/mapping/CMap.h"
#include "CDefHandler.h"
#include "../lib/CConfigHandler.h"
@ -207,7 +207,7 @@ void CMapHandler::borderAndTerrainBitmapInit()
terBitmapNum = 17;
else if(i==(sizes.x) && j==(sizes.y))
terBitmapNum = 18;
else if(j == -1 && i > -1 && i < sizes.y)
else if(j == -1 && i > -1 && i < sizes.x)
terBitmapNum = rand.nextInt(22, 23);
else if(i == -1 && j > -1 && j < sizes.y)
terBitmapNum = rand.nextInt(33, 34);
@ -541,10 +541,8 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std::
//pick graphics of hero (or boat if hero is sailing)
if (themp->boat)
iv = &graphics->boatAnims[themp->boat->subID]->ourImages;
else if (themp->sex)
iv = &graphics->heroAnims[themp->type->heroClass->imageMapFemale]->ourImages;
else
iv = &graphics->heroAnims[themp->type->heroClass->imageMapMale]->ourImages;
iv = &graphics->heroAnims[themp->appearance.animationFile]->ourImages;
//pick appropriate flag set
if(themp->boat)
@ -1073,7 +1071,7 @@ void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terN
}
if(t.hasFavourableWinds())
out = CGI->generaltexth->names[Obj::FAVORABLE_WINDS];
out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS);
else if(terName)
out = CGI->generaltexth->terrainNames[t.terType];
}

View File

@ -1,675 +1,9 @@
//Resources: Wood, Mercury, Ore, Sulfur, Crystal, Gems, Gold
//Artifacts: Treasure, Minor, Major, Relic
//NOTE: all H3M banks were moved to objects/creatureBanks.json
//Remaining part should be moved to WoG mod
{
"banks": [
{
"name" : "Cyclops Stockpile",
"levels": [
{
"chance": 30,
"guards": [ { "number": 20, "id": 94 } ],
"upgrade_chance": 50,
"combat_value": 506,
"reward_resources":
{
"wood" : 4,
"mercury" : 4,
"ore" : 4,
"sulfur" : 4,
"crystal" : 4,
"gems" : 4,
"gold" : 0
},
"value": 10000,
"profitability": 20,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 30, "id": 94 } ],
"upgrade_chance": 50,
"combat_value": 760,
"reward_resources":
{
"wood" : 6,
"mercury" : 6,
"ore" : 6,
"sulfur" : 6,
"crystal" : 6,
"gems" : 6
},
"value": 15000,
"profitability": 20,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 40, "id": 94 } ],
"upgrade_chance": 50,
"combat_value": 1013,
"reward_resources":
{
"wood" : 8,
"mercury" : 8,
"ore" : 8,
"sulfur" : 8,
"crystal" : 8,
"gems" : 8
},
"value": 20000,
"profitability": 20,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 50, "id": 94 } ],
"upgrade_chance": 50,
"combat_value": 1266,
"reward_resources":
{
"wood" : 10,
"mercury" : 10,
"ore" : 10,
"sulfur" : 10,
"crystal" : 10,
"gems" : 10
},
"value": 25000,
"profitability": 20,
"easiest": 250
}
]
},
{
"name" : "Dwarven Treasury",
"levels": [
{
"chance": 30,
"guards": [ { "number": 50, "id": 16 } ],
"upgrade_chance": 50,
"combat_value": 194,
"reward_resources":
{
"crystal" : 2,
"gold" : 2500
},
"value": 3500,
"profitability": 18,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 75, "id": 16 } ],
"upgrade_chance": 50,
"combat_value": 291,
"reward_resources":
{
"crystal" : 3,
"gold" : 4000
},
"value": 5500,
"profitability": 19,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 100, "id": 16 } ],
"upgrade_chance": 50,
"combat_value": 388,
"reward_resources":
{
"crystal" : 5,
"gold" : 5000
},
"value": 7500,
"profitability": 19,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 150, "id": 16 } ],
"upgrade_chance": 50,
"combat_value": 582,
"reward_resources":
{
"crystal" : 10,
"gold" : 7500
},
"value": 12500,
"profitability": 21,
"easiest": 300
}
]
},
{
"name" : "Griffin Conservatory",
"levels": [
{
"chance": 30,
"guards": [ { "number": 50, "id": 4 } ],
"upgrade_chance": 50,
"combat_value": 351,
"reward_creatures": [ { "number": 1, "id": 12 } ],
"value": 3000,
"profitability": 9,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 100, "id": 4 } ],
"upgrade_chance": 50,
"combat_value": 702,
"reward_creatures": [ { "number": 2, "id": 12 } ],
"value": 6000,
"profitability": 9,
"easiest": 200
},
{
"chance": 30,
"guards": [ { "number": 150, "id": 4 } ],
"upgrade_chance": 50,
"combat_value": 1053,
"reward_creatures": [ { "number": 3, "id": 12 } ],
"value": 9000,
"profitability": 9,
"easiest": 300
},
{
"chance": 10,
"guards": [ { "number": 200, "id": 4 } ],
"upgrade_chance": 50,
"combat_value": 1404,
"reward_creatures": [ { "number": 4, "id": 12 } ],
"value": 12000,
"profitability": 9,
"easiest": 400
}
]
},
{
"name" : "Imp Cache",
"levels": [
{
"chance": 30,
"guards": [ { "number": 100, "id": 42 } ],
"upgrade_chance": 50,
"combat_value": 100,
"reward_resources":
{
"wood" : 0,
"mercury" : 2,
"ore" : 0,
"sulfur" : 0,
"crystal" : 0,
"gems" : 0,
"gold" : 1000
},
"value": 2000,
"profitability": 20,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 150, "id": 42 } ],
"upgrade_chance": 50,
"combat_value": 150,
"reward_resources":
{
"mercury" : 3,
"gold" : 1500
},
"value": 3000,
"profitability": 20,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 200, "id": 42 } ],
"upgrade_chance": 50,
"combat_value": 200,
"reward_resources":
{
"mercury" : 4,
"gold" : 2000
},
"value": 4000,
"profitability": 20,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 300, "id": 42 } ],
"upgrade_chance": 50,
"combat_value": 300,
"reward_resources":
{
"mercury" : 6,
"gold" : 3000
},
"value": 6000,
"profitability": 20,
"easiest": 300
}
]
},
{
"name" : "Medusa Stores",
"levels": [
{
"chance": 30,
"guards": [ { "number": 20, "id": 76 } ],
"upgrade_chance": 50,
"combat_value": 207,
"reward_resources":
{
"sulfur" : 5,
"gold" : 2000
},
"value": 4500,
"profitability": 22,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 30, "id": 76 } ],
"upgrade_chance": 50,
"combat_value": 310,
"reward_resources":
{
"sulfur" : 6,
"gold" : 3000
},
"value": 6000,
"profitability": 19,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 40, "id": 76 } ],
"upgrade_chance": 50,
"combat_value": 414,
"reward_resources":
{
"sulfur" : 8,
"gold" : 4000
},
"value": 8000,
"profitability": 19,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 50, "id": 76 } ],
"upgrade_chance": 50,
"combat_value": 517,
"reward_resources":
{
"sulfur" : 10,
"gold" : 5000
},
"value": 10000,
"profitability": 19,
"easiest": 250
}
]
},
{
"name" : "Naga Bank",
"levels": [
{
"chance": 30,
"guards": [ { "number": 10, "id": 38 } ],
"upgrade_chance": 50,
"combat_value": 403,
"reward_resources":
{
"gems" : 8,
"gold" : 4000
},
"value": 8000,
"profitability": 20,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 15, "id": 38 } ],
"upgrade_chance": 50,
"combat_value": 605,
"reward_resources":
{
"gems" : 12,
"gold" : 6000
},
"value": 12000,
"profitability": 20,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 20, "id": 38 } ],
"upgrade_chance": 50,
"combat_value": 806,
"reward_resources":
{
"gems" : 16,
"gold" : 8000
},
"value": 16000,
"profitability": 20,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 30, "id": 38 } ],
"upgrade_chance": 50,
"combat_value": 1210,
"reward_resources":
{
"gems" : 24,
"gold" : 12000
},
"value": 24000,
"profitability": 20,
"easiest": 300
}
]
},
{
"name" : "Dragon Fly Hive",
"levels": [
{
"chance": 30,
"guards": [ { "number": 30, "id": 105} ],
"upgrade_chance": 0,
"combat_value": 154,
"reward_creatures": [ { "number": 4, "id": 108 } ],
"value": 3200,
"profitability": 21,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 45, "id": 105 } ],
"upgrade_chance": 0,
"combat_value": 230,
"reward_creatures": [ { "number": 6, "id": 108 } ],
"value": 4800,
"profitability": 21,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 60, "id": 105 } ],
"upgrade_chance": 0,
"combat_value": 307,
"reward_creatures": [ { "number": 8, "id": 108 } ],
"value": 6400,
"profitability": 21,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 90, "id": 105 } ],
"upgrade_chance": 0,
"combat_value": 461,
"reward_creatures": [ { "number": 12, "id": 108 } ],
"value": 9600,
"profitability": 21,
"easiest": 300
}
]
},
{
"name" : "Shipwreck",
"levels": [
{
"chance": 30,
"guards": [ { "number": 10, "id": 60 } ],
"upgrade_chance": 0,
"combat_value": 31,
"reward_resources":
{
"gold" : 2000
},
"value": 2000,
"profitability": 65,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 15, "id": 60 } ],
"upgrade_chance": 0,
"combat_value": 46,
"reward_resources":
{
"gold" : 3000
},
"value": 3000,
"profitability": 65,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 25, "id": 60 } ],
"upgrade_chance": 0,
"combat_value": 77,
"reward_resources":
{
"gold" : 4000
},
"reward_artifacts": [ 1, 0, 0, 0 ],
"value": 5000,
"profitability": 65,
"easiest": 250
},
{
"chance": 10,
"guards": [ { "number": 50, "id": 60 } ],
"upgrade_chance": 0,
"combat_value": 154,
"reward_resources":
{
"gold" : 5000
},
"reward_artifacts": [ 0, 1, 0, 0 ],
"value": 7000,
"profitability": 45,
"easiest": 500
}
]
},
{
"name" : "Derelict Ship",
"levels": [
{
"chance": 30,
"guards": [ { "number": 20, "id": 115 } ],
"upgrade_chance": 0,
"combat_value": 138,
"reward_resources":
{
"gold" : 3000
},
"value": 3000,
"profitability": 22,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 30, "id": 115 } ],
"upgrade_chance": 0,
"combat_value": 207,
"reward_resources":
{
"gold" : 3000
},
"reward_artifacts": [ 1, 0, 0, 0 ],
"value": 4000,
"profitability": 19,
"easiest": 150
},
{
"chance": 30,
"guards": [ { "number": 40, "id": 115 } ],
"upgrade_chance": 0,
"combat_value": 276,
"reward_resources":
{
"gold" : 4000
},
"reward_artifacts": [ 1, 0, 0, 0 ],
"value": 5000,
"profitability": 18,
"easiest": 200
},
{
"chance": 10,
"guards": [ { "number": 60, "id": 115 } ],
"upgrade_chance": 0,
"combat_value": 414,
"reward_resources":
{
"gold" : 6000
},
"reward_artifacts": [ 0, 1, 0, 0 ],
"value": 8000,
"profitability": 19,
"easiest": 300
}
]
},
{
"name" : "Crypt",
"levels": [
{
"chance": 30,
"guards": [ { "number": 30, "id": 56 }, { "number": 20, "id": 58 }, { "number": 0, "id": 60 } , { "number": 0, "id": 62 } ],
"upgrade_chance": 0,
"combat_value": 75,
"reward_resources":
{
"gold" : 1500
},
"value": 1500,
"profitability": 20,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 25, "id": 56 }, { "number": 20, "id": 58 }, { "number": 5, "id": 60 }, { "number": 0, "id": 62 } ],
"upgrade_chance": 0,
"combat_value": 94,
"reward_resources":
{
"gold" : 2000
},
"value": 2000,
"profitability": 21,
"easiest": 126
},
{
"chance": 30,
"guards": [ { "number": 20, "id": 56 }, { "number": 20, "id": 58 }, { "number": 10, "id": 60 }, { "number": 5, "id": 62 } ],
"upgrade_chance": 0,
"combat_value": 169,
"reward_resources":
{
"gold" : 2500
},
"reward_artifacts": [ 1, 0, 0, 0 ],
"value": 3500,
"profitability": 21,
"easiest": 225
},
{
"chance": 10,
"guards": [ { "number": 20, "id": 56 }, { "number": 20, "id": 58 }, { "number": 10, "id": 60 }, { "number": 10, "id": 62 } ],
"upgrade_chance": 0,
"combat_value": 225,
"reward_resources":
{
"gold" : 5000
},
"reward_artifacts": [ 1, 0, 0, 0 ],
"value": 6000,
"profitability": 27,
"easiest": 299
}
]
},
{
"name" : "Dragon Utopia",
"levels": [
{
"chance": 30,
"guards": [ { "number": 8, "id": 26 }, { "number": 5, "id": 82 }, { "number": 2, "id": 27 }, { "number": 1, "id": 83 } ],
"upgrade_chance": 0,
"combat_value": 769,
"reward_resources":
{
"gold" : 20000
},
"reward_artifacts": [ 1, 1, 1, 1 ],
"value": 38000,
"profitability": 21,
"easiest": 100
},
{
"chance": 30,
"guards": [ { "number": 8, "id": 26 }, { "number": 6, "id": 82 }, { "number": 3, "id": 27 }, { "number": 2, "id": 83 } ],
"upgrade_chance": 0,
"combat_value": 209,
"reward_resources":
{
"gold" : 30000
},
"reward_artifacts": [ 0, 1, 1, 2 ],
"value": 57000,
"profitability": 26,
"easiest": 125
},
{
"chance": 30,
"guards": [ { "number": 8, "id": 26 }, { "number": 6, "id": 82 }, { "number": 4, "id": 27 }, { "number": 3, "id": 83 } ],
"upgrade_chance": 0,
"combat_value": 556,
"reward_resources":
{
"gold" : 40000
},
"reward_artifacts": [ 0, 0, 1, 3 ],
"value": 75000,
"profitability": 29,
"easiest": 145
},
{
"chance": 10,
"guards": [ { "number": 8, "id": 26 }, { "number": 7, "id": 82 }, { "number": 6, "id": 27 }, { "number": 5, "id": 83 } ],
"upgrade_chance": 0,
"combat_value": 343,
"reward_resources":
{
"gold" : 50000
},
"reward_artifacts": [ 0, 0, 0, 4 ],
"value": 90000,
"profitability": 27,
"easiest": 189
}
]
},
{
"name" : "Hunting Lodge",
"levels": [
@ -1252,21 +586,6 @@
"easiest": 250
}
]
},
{
"name" : "Pyramid",
"levels": [
{
"chance": 100,
"guards": [ { "number": 20, "id": 116 }, { "number": 10, "id": 117 }, { "number": 20, "id": 116 }, { "number": 10, "id": 117 } ],
"upgrade_chance": 0,
"combat_value": 786,
"value": 15000,
"profitability": 19,
"easiest": 100
}
]
}
]
}

View File

@ -8,7 +8,8 @@
"creature" : 150,
"faction" : 9,
"hero" : 156,
"spell" : 81,
"spell" : 81,
"object" : 256,
"mapVersion" : 28 // max supported version, SoD
},

View File

@ -1,108 +0,0 @@
{
// Indicate which dwelling produces which creature
// Note that it is 1<->n connection since
// a creature can be produced by more than one dwelling.
"dwellings": [
{ "dwelling": 0, "creature": 106 },
{ "dwelling": 1, "creature": 96 },
{ "dwelling": 2, "creature": 74 },
{ "dwelling": 3, "creature": 66 },
{ "dwelling": 4, "creature": 68 },
{ "dwelling": 5, "creature": 10 },
{ "dwelling": 6, "creature": 14 },
{ "dwelling": 7, "creature": 112 },
{ "dwelling": 8, "creature": 12 },
{ "dwelling": 9, "creature": 94 },
{ "dwelling": 10, "creature": 54 },
{ "dwelling": 11, "creature": 104 },
{ "dwelling": 12, "creature": 16 },
{ "dwelling": 13, "creature": 113 },
{ "dwelling": 14, "creature": 52 },
{ "dwelling": 15, "creature": 18 },
{ "dwelling": 16, "creature": 114 },
{ "dwelling": 17, "creature": 30 },
{ "dwelling": 18, "creature": 36 },
{ "dwelling": 19, "creature": 86 },
{ "dwelling": 20, "creature": 98 },
{ "dwelling": 21, "creature": 84 },
{ "dwelling": 22, "creature": 44 },
{ "dwelling": 23, "creature": 102 },
{ "dwelling": 24, "creature": 26 },
{ "dwelling": 25, "creature": 4 },
{ "dwelling": 26, "creature": 72 },
{ "dwelling": 27, "creature": 46 },
{ "dwelling": 28, "creature": 110 },
{ "dwelling": 29, "creature": 42 },
{ "dwelling": 30, "creature": 100 },
{ "dwelling": 31, "creature": 34 },
{ "dwelling": 32, "creature": 80 },
{ "dwelling": 33, "creature": 76 },
{ "dwelling": 34, "creature": 78 },
{ "dwelling": 35, "creature": 8 },
{ "dwelling": 36, "creature": 38 },
{ "dwelling": 37, "creature": 48 },
{ "dwelling": 38, "creature": 90 },
{ "dwelling": 39, "creature": 88 },
{ "dwelling": 40, "creature": 50 },
{ "dwelling": 41, "creature": 82 },
{ "dwelling": 42, "creature": 92 },
{ "dwelling": 43, "creature": 28 },
{ "dwelling": 44, "creature": 40 },
{ "dwelling": 45, "creature": 22 },
{ "dwelling": 46, "creature": 70 },
{ "dwelling": 47, "creature": 115 },
{ "dwelling": 48, "creature": 60 },
{ "dwelling": 49, "creature": 108 },
{ "dwelling": 50, "creature": 20 },
{ "dwelling": 51, "creature": 24 },
{ "dwelling": 52, "creature": 64 },
{ "dwelling": 53, "creature": 62 },
{ "dwelling": 54, "creature": 56 },
{ "dwelling": 55, "creature": 58 },
{ "dwelling": 56, "creature": 0 },
{ "dwelling": 57, "creature": 2 },
{ "dwelling": 58, "creature": 6 },
{ "dwelling": 59, "creature": 118 },
{ "dwelling": 60, "creature": 120 },
{ "dwelling": 61, "creature": 130 },
{ "dwelling": 62, "creature": 132 },
{ "dwelling": 63, "creature": 133 },
{ "dwelling": 64, "creature": 134 },
{ "dwelling": 65, "creature": 135 },
{ "dwelling": 66, "creature": 136 },
{ "dwelling": 67, "creature": 137 },
{ "dwelling": 68, "creature": 24 },
{ "dwelling": 69, "creature": 112 },
{ "dwelling": 70, "creature": 113 },
{ "dwelling": 71, "creature": 114 },
{ "dwelling": 72, "creature": 115 },
{ "dwelling": 73, "creature": 138 },
{ "dwelling": 74, "creature": 139 },
{ "dwelling": 75, "creature": 140 },
{ "dwelling": 76, "creature": 141 },
{ "dwelling": 77, "creature": 142 },
{ "dwelling": 78, "creature": 143 },
{ "dwelling": 79, "creature": 144 },
{ "dwelling": 80, "creature": 150 },
{ "dwelling": 81, "creature": 151 },
{ "dwelling": 82, "creature": 152 },
{ "dwelling": 83, "creature": 153 },
{ "dwelling": 84, "creature": 154 },
{ "dwelling": 85, "creature": 155 },
{ "dwelling": 86, "creature": 156 },
{ "dwelling": 87, "creature": 157 },
{ "dwelling": 88, "creature": 158 },
{ "dwelling": 89, "creature": 171 },
{ "dwelling": 90, "creature": 170 },
{ "dwelling": 91, "creature": 168 },
{ "dwelling": 92, "creature": 172 },
{ "dwelling": 93, "creature": 164 },
{ "dwelling": 94, "creature": 169 },
{ "dwelling": 95, "creature": 173 },
{ "dwelling": 96, "creature": 192 },
{ "dwelling": 97, "creature": 193 },
{ "dwelling": 98, "creature": 194 },
{ "dwelling": 99, "creature": 195 },
{ "dwelling": 100, "creature": 196 }
]
}

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCcasx0.def",
"village" : "AVCCAST0.DEF",
"capitol" : "AVCCASZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCcasx0.def" },
"village" : { "animation" : "AVCCAST0.DEF" },
"capitol" : { "animation" : "AVCCASZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "avchforx.def",
"village" : "AVCHFOR0.DEF",
"capitol" : "AVCHFORZ.DEF"
"templates" : {
"castle" : { "animation" : "avchforx.def" },
"village" : { "animation" : "AVCHFOR0.DEF" },
"capitol" : { "animation" : "AVCHFORZ.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCdunx0.def",
"village" : "AVCDUNG0.DEF",
"capitol" : "AVCDUNZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCdunx0.def" },
"village" : { "animation" : "AVCDUNG0.DEF" },
"capitol" : { "animation" : "AVCDUNZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCftrx0.def",
"village" : "AVCFTRT0.DEF",
"capitol" : "AVCFORZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCftrx0.def" },
"village" : { "animation" : "AVCFTRT0.DEF" },
"capitol" : { "animation" : "AVCFORZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCinfx0.def",
"village" : "AVCINFT0.DEF",
"capitol" : "AVCINFZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCinfx0.def" },
"village" : { "animation" : "AVCINFT0.DEF" },
"capitol" : { "animation" : "AVCINFZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCnecx0.def",
"village" : "AVCNECR0.DEF",
"capitol" : "AVCNECZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCnecx0.def" },
"village" : { "animation" : "AVCNECR0.DEF" },
"capitol" : { "animation" : "AVCNECZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCramx0.def",
"village" : "AVCRAMP0.DEF",
"capitol" : "AVCRAMZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCramx0.def" },
"village" : { "animation" : "AVCRAMP0.DEF" },
"capitol" : { "animation" : "AVCRAMZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCstrx0.def",
"village" : "AVCSTRO0.DEF",
"capitol" : "AVCSTRZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCstrx0.def" },
"village" : { "animation" : "AVCSTRO0.DEF" },
"capitol" : { "animation" : "AVCSTRZ0.DEF" }
}
},
"structures" :
{

View File

@ -66,11 +66,13 @@
},
"town" :
{
"adventureMap" :
"mapObject" :
{
"castle" : "AVCtowx0.def",
"village" : "AVCTOWR0.DEF",
"capitol" : "AVCTOWZ0.DEF"
"templates" : {
"castle" : { "animation" : "AVCtowx0.def" },
"village" : { "animation" : "AVCTOWR0.DEF" },
"capitol" : { "animation" : "AVCTOWZ0.DEF" }
}
},
"structures" :
{

View File

@ -45,6 +45,15 @@
"config/heroes/special.json"
],
"objects" :
[
"config/objects/generic.json",
"config/objects/moddables.json",
"config/objects/creatureBanks.json",
"config/objects/dwellings.json",
"config/objects/rewardable.json"
],
"artifacts" :
[
"config/artifacts.json"

View File

@ -6,11 +6,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "zealot",
"animation":
{
"battle" : { "male" : "CH00.DEF", "female" : "CH01.DEF" },
"map": { "male" : "AH00_.def", "female" : "AH00_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH00_.def" } } },
"animation": { "battle" : { "male" : "CH00.DEF", "female" : "CH01.DEF" } }
},
"cleric" :
{
@ -19,11 +16,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "zealot",
"animation":
{
"battle" : { "male" : "CH00.DEF", "female" : "CH01.DEF" },
"map": { "male" : "AH01_.def", "female" : "AH01_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH01_.def" } } },
"animation": { "battle" : { "male" : "CH00.DEF", "female" : "CH01.DEF" } }
},
"ranger" :
{
@ -32,11 +26,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "grandElf",
"animation":
{
"battle" : { "male" : "CH02.DEF", "female" : "CH03.DEF" },
"map": { "male" : "AH02_.def", "female" : "AH02_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH02_.def" } } },
"animation": { "battle" : { "male" : "CH02.DEF", "female" : "CH03.DEF" } }
},
"druid" :
{
@ -45,11 +36,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "grandElf",
"animation":
{
"battle" : { "male" : "CH02.DEF", "female" : "CH03.DEF" },
"map": { "male" : "AH03_.def", "female" : "AH03_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH03_.def" } } },
"animation": { "battle" : { "male" : "CH02.DEF", "female" : "CH03.DEF" } }
},
"alchemist" :
{
@ -58,11 +46,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "archMage",
"animation":
{
"battle" : { "male" : "CH05.DEF", "female" : "CH04.DEF" },
"map": { "male" : "AH04_.def", "female" : "AH04_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH04_.def" } } },
"animation": { "battle" : { "male" : "CH05.DEF", "female" : "CH04.DEF" } }
},
"wizard" :
{
@ -71,11 +56,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "archMage",
"animation":
{
"battle" : { "male" : "CH05.DEF", "female" : "CH04.DEF" },
"map": { "male" : "AH05_.def", "female" : "AH05_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH05_.def" } } },
"animation": { "battle" : { "male" : "CH05.DEF", "female" : "CH04.DEF" } }
},
"demoniac" :
{
@ -84,11 +66,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "magog",
"animation":
{
"battle" : { "male" : "CH06.DEF", "female" : "CH07.DEF" },
"map": { "male" : "AH06_.def", "female" : "AH06_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH06_.def" } } },
"animation": { "battle" : { "male" : "CH06.DEF", "female" : "CH07.DEF" } }
},
"heretic" :
{
@ -97,11 +76,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "magog",
"animation":
{
"battle" : { "male" : "CH06.DEF", "female" : "CH07.DEF" },
"map": { "male" : "AH07_.def", "female" : "AH07_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH07_.def" } } },
"animation": { "battle" : { "male" : "CH06.DEF", "female" : "CH07.DEF" } }
},
"deathknight" :
{
@ -110,11 +86,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "powerLich",
"animation":
{
"battle" : { "male" : "CH08.DEF", "female" : "CH09.DEF" },
"map": { "male" : "AH08_.def", "female" : "AH08_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH08_.def" } } },
"animation": { "battle" : { "male" : "CH08.DEF", "female" : "CH09.DEF" } }
},
"necromancer" :
{
@ -123,11 +96,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "powerLich",
"animation":
{
"battle" : { "male" : "CH08.DEF", "female" : "CH09.DEF" },
"map": { "male" : "AH09_.def", "female" : "AH09_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH09_.def" } } },
"animation": { "battle" : { "male" : "CH08.DEF", "female" : "CH09.DEF" } }
},
"warlock" :
{
@ -136,11 +106,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "medusaQueen",
"animation":
{
"battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" },
"map": { "male" : "AH10_.def", "female" : "AH10_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH10_.def" } } },
"animation": { "battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" } }
},
"overlord" :
{
@ -149,11 +116,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "medusaQueen",
"animation":
{
"battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" },
"map": { "male" : "AH11_.def", "female" : "AH11_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH11_.def" } } },
"animation": { "battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" } }
},
"barbarian" :
{
@ -162,11 +126,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "orcChieftain",
"animation":
{
"battle" : { "male" : "CH013.DEF", "female" : "CH012.DEF" },
"map": { "male" : "AH12_.def", "female" : "AH12_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH12_.def" } } },
"animation": { "battle" : { "male" : "CH013.DEF", "female" : "CH012.DEF" } }
},
"battlemage" :
{
@ -175,11 +136,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "orcChieftain",
"animation":
{
"battle" : { "male" : "CH013.DEF", "female" : "CH012.DEF" },
"map": { "male" : "AH13_.def", "female" : "AH13_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH13_.def" } } },
"animation": { "battle" : { "male" : "CH013.DEF", "female" : "CH012.DEF" } }
},
"beastmaster" :
{
@ -188,11 +146,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "lizardWarrior",
"animation":
{
"battle" : { "male" : "CH014.DEF", "female" : "CH015.DEF" },
"map": { "male" : "AH14_.def", "female" : "AH14_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH14_.def" } } },
"animation": { "battle" : { "male" : "CH014.DEF", "female" : "CH015.DEF" } }
},
"witch" :
{
@ -201,11 +156,8 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "lizardWarrior",
"animation":
{
"battle" : { "male" : "CH014.DEF", "female" : "CH015.DEF" },
"map": { "male" : "AH15_.def", "female" : "AH15_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH15_.def" } } },
"animation": { "battle" : { "male" : "CH014.DEF", "female" : "CH015.DEF" } }
},
"planeswalker" :
{
@ -214,11 +166,8 @@
"defaultTavern" : 5,
"affinity" : "might",
"commander" : "iceElemental",
"animation":
{
"battle" : { "male" : "CH16.DEF", "female" : "CH16.DEF" },
"map": { "male" : "AH16_.def", "female" : "AH16_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH16_.def" } } },
"animation": { "battle" : { "male" : "CH16.DEF", "female" : "CH16.DEF" } }
},
"elementalist" :
{
@ -227,10 +176,7 @@
"defaultTavern" : 5,
"affinity" : "magic",
"commander" : "iceElemental",
"animation":
{
"battle" : { "male" : "CH17.DEF", "female" : "CH17.DEF" },
"map": { "male" : "AH17_.def", "female" : "AH17_.def" }
}
"mapObject" : { "templates" : { "default" : { "animation" : "AH17_.def" } } },
"animation": { "battle" : { "male" : "CH17.DEF", "female" : "CH17.DEF" } }
}
}

View File

@ -0,0 +1,973 @@
{
"creatureBank" : {
"index" :16,
"handler": "bank",
"types" : {
"cyclopsStockpile" :
{
"index" : 0,
"name" : "Cyclops Stockpile",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 4, "type": "cyclop" },
{ "amount": 4, "type": "cyclop" },
{ "amount": 4, "type": "cyclop", "upgradeChance": 50 },
{ "amount": 4, "type": "cyclop" },
{ "amount": 4, "type": "cyclop" }
],
"combat_value": 506,
"reward" : {
"value": 10000,
"resources":
{
"wood" : 4,
"mercury" : 4,
"ore" : 4,
"sulfur" : 4,
"crystal" : 4,
"gems" : 4,
"gold" : 0
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 6, "type": "cyclop" },
{ "amount": 6, "type": "cyclop" },
{ "amount": 6, "type": "cyclop", "upgradeChance": 50 },
{ "amount": 6, "type": "cyclop" },
{ "amount": 6, "type": "cyclop" }
],
"combat_value": 760,
"reward" : {
"value": 15000,
"resources":
{
"wood" : 6,
"mercury" : 6,
"ore" : 6,
"sulfur" : 6,
"crystal" : 6,
"gems" : 6
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 8, "type": "cyclop" },
{ "amount": 8, "type": "cyclop" },
{ "amount": 8, "type": "cyclop", "upgradeChance": 50 },
{ "amount": 8, "type": "cyclop" },
{ "amount": 8, "type": "cyclop" }
],
"combat_value": 1013,
"reward" : {
"value": 20000,
"resources":
{
"wood" : 8,
"mercury" : 8,
"ore" : 8,
"sulfur" : 8,
"crystal" : 8,
"gems" : 8
}
}
},
{
"chance": 10,
"guards": [
{ "amount": 10, "type": "cyclop" },
{ "amount": 10, "type": "cyclop" },
{ "amount": 10, "type": "cyclop", "upgradeChance": 50 },
{ "amount": 10, "type": "cyclop" },
{ "amount": 10, "type": "cyclop" }
],
"combat_value": 1266,
"reward" : {
"value": 25000,
"resources":
{
"wood" : 10,
"mercury" : 10,
"ore" : 10,
"sulfur" : 10,
"crystal" : 10,
"gems" : 10
}
}
}
]
},
"dwarvenTreasury" : {
"index" : 1,
"resetDuraition" : 28,
"name" : "Dwarven Treasury",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 10, "type": "dwarf" },
{ "amount": 10, "type": "dwarf" },
{ "amount": 10, "type": "dwarf", "upgradeChance": 50 },
{ "amount": 10, "type": "dwarf" },
{ "amount": 10, "type": "dwarf" }
],
"combat_value": 194,
"reward" : {
"value": 3500,
"resources":
{
"crystal" : 2,
"gold" : 2500
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 15, "type": "dwarf" },
{ "amount": 15, "type": "dwarf" },
{ "amount": 15, "type": "dwarf", "upgradeChance": 50 },
{ "amount": 15, "type": "dwarf" },
{ "amount": 15, "type": "dwarf" }
],
"combat_value": 291,
"reward" : {
"value": 5500,
"resources":
{
"crystal" : 3,
"gold" : 4000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 20, "type": "dwarf" },
{ "amount": 20, "type": "dwarf" },
{ "amount": 20, "type": "dwarf", "upgradeChance": 50 },
{ "amount": 20, "type": "dwarf" },
{ "amount": 20, "type": "dwarf" }
],
"combat_value": 388,
"reward" : {
"value": 7500,
"resources":
{
"crystal" : 5,
"gold" : 5000
}
}
},
{
"chance": 10,
"guards": [
{ "amount": 30, "type": "dwarf" },
{ "amount": 30, "type": "dwarf" },
{ "amount": 30, "type": "dwarf", "upgradeChance": 50 },
{ "amount": 30, "type": "dwarf" },
{ "amount": 30, "type": "dwarf" }
],
"combat_value": 582,
"reward" : {
"value": 12500,
"resources":
{
"crystal" : 10,
"gold" : 7500
}
}
}
]
},
"griffinConservatory" : {
"index" : 2,
"resetDuraition" : 28,
"name" : "Griffin Conservatory",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 10, "type": "griffin" },
{ "amount": 10, "type": "griffin" },
{ "amount": 10, "type": "griffin", "upgradeChance": 50 },
{ "amount": 10, "type": "griffin" },
{ "amount": 10, "type": "griffin" }
],
"combat_value": 351,
"reward" : {
"value": 3000,
"creatures": [ { "amount": 1, "type": "angel" } ]
}
},
{
"chance": 30,
"guards": [
{ "amount": 20, "type": "griffin" },
{ "amount": 20, "type": "griffin" },
{ "amount": 20, "type": "griffin", "upgradeChance": 50 },
{ "amount": 20, "type": "griffin" },
{ "amount": 20, "type": "griffin" }
],
"combat_value": 702,
"reward" : {
"value": 6000,
"creatures": [ { "amount": 2, "type": "angel" } ]
}
},
{
"chance": 30,
"guards": [
{ "amount": 30, "type": "griffin" },
{ "amount": 30, "type": "griffin" },
{ "amount": 30, "type": "griffin", "upgradeChance": 50 },
{ "amount": 30, "type": "griffin" },
{ "amount": 30, "type": "griffin" }
],
"combat_value": 1053,
"reward" : {
"value": 9000,
"creatures": [ { "amount": 3, "type": "angel" } ]
}
},
{
"chance": 10,
"guards": [
{ "amount": 40, "type": "griffin" },
{ "amount": 40, "type": "griffin" },
{ "amount": 40, "type": "griffin", "upgradeChance": 50 },
{ "amount": 40, "type": "griffin" },
{ "amount": 40, "type": "griffin" }
],
"combat_value": 1404,
"reward" : {
"value": 12000,
"creatures": [ { "amount": 4, "type": "angel" } ]
}
}
]
},
"inpCache" : {
"index" : 3,
"resetDuraition" : 28,
"name" : "Imp Cache",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 20, "type": "imp" },
{ "amount": 20, "type": "imp" },
{ "amount": 20, "type": "imp", "upgradeChance": 50 },
{ "amount": 20, "type": "imp" },
{ "amount": 20, "type": "imp" }
],
"combat_value": 100,
"reward" : {
"value": 2000,
"resources":
{
"wood" : 0,
"mercury" : 2,
"ore" : 0,
"sulfur" : 0,
"crystal" : 0,
"gems" : 0,
"gold" : 1000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 30, "type": "imp" },
{ "amount": 30, "type": "imp" },
{ "amount": 30, "type": "imp", "upgradeChance": 50 },
{ "amount": 30, "type": "imp" },
{ "amount": 30, "type": "imp" }
],
"combat_value": 150,
"reward" : {
"value": 3000,
"resources":
{
"mercury" : 3,
"gold" : 1500
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 40, "type": "imp" },
{ "amount": 40, "type": "imp" },
{ "amount": 40, "type": "imp", "upgradeChance": 50 },
{ "amount": 40, "type": "imp" },
{ "amount": 40, "type": "imp" }
],
"combat_value": 200,
"reward" : {
"value": 4000,
"resources":
{
"mercury" : 4,
"gold" : 2000
}
}
},
{
"chance": 10,
"guards": [
{ "amount": 60, "type": "imp" },
{ "amount": 60, "type": "imp" },
{ "amount": 60, "type": "imp", "upgradeChance": 50 },
{ "amount": 60, "type": "imp" },
{ "amount": 60, "type": "imp" }
],
"combat_value": 300,
"reward" : {
"value": 6000,
"resources":
{
"mercury" : 6,
"gold" : 3000
}
}
}
]
},
"medusaStore" : {
"index" : 4,
"resetDuraition" : 28,
"name" : "Medusa Stores",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 4, "type": "medusa" },
{ "amount": 4, "type": "medusa" },
{ "amount": 4, "type": "medusa", "upgradeChance": 50 },
{ "amount": 4, "type": "medusa" },
{ "amount": 4, "type": "medusa" }
],
"combat_value": 207,
"reward" : {
"value": 4500,
"resources":
{
"sulfur" : 5,
"gold" : 2000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 6, "type": "medusa" },
{ "amount": 6, "type": "medusa" },
{ "amount": 6, "type": "medusa", "upgradeChance": 50 },
{ "amount": 6, "type": "medusa" },
{ "amount": 6, "type": "medusa" }
],
"combat_value": 310,
"reward" : {
"value": 6000,
"resources":
{
"sulfur" : 6,
"gold" : 3000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 8, "type": "medusa" },
{ "amount": 8, "type": "medusa" },
{ "amount": 8, "type": "medusa", "upgradeChance": 50 },
{ "amount": 8, "type": "medusa" },
{ "amount": 8, "type": "medusa" }
],
"combat_value": 414,
"reward" : {
"value": 8000,
"resources":
{
"sulfur" : 8,
"gold" : 4000
}
}
},
{
"chance": 10,
"guards": [
{ "amount": 10, "type": "medusa" },
{ "amount": 10, "type": "medusa" },
{ "amount": 10, "type": "medusa", "upgradeChance": 50 },
{ "amount": 10, "type": "medusa" },
{ "amount": 10, "type": "medusa" }
],
"combat_value": 517,
"reward" : {
"value": 10000,
"resources":
{
"sulfur" : 10,
"gold" : 5000
}
}
}
]
},
"nagaBank" : {
"index" : 5,
"resetDuraition" : 28,
"name" : "Naga Bank",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 2, "type": "naga" },
{ "amount": 2, "type": "naga" },
{ "amount": 2, "type": "naga", "upgradeChance": 50 },
{ "amount": 2, "type": "naga" },
{ "amount": 2, "type": "naga" }
],
"combat_value": 403,
"reward" : {
"value": 8000,
"resources":
{
"gems" : 8,
"gold" : 4000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 3, "type": "naga" },
{ "amount": 3, "type": "naga" },
{ "amount": 3, "type": "naga", "upgradeChance": 50 },
{ "amount": 3, "type": "naga" },
{ "amount": 3, "type": "naga" }
],
"combat_value": 605,
"reward" : {
"value": 12000,
"resources":
{
"gems" : 12,
"gold" : 6000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 4, "type": "naga" },
{ "amount": 4, "type": "naga" },
{ "amount": 4, "type": "naga", "upgradeChance": 50 },
{ "amount": 4, "type": "naga" },
{ "amount": 4, "type": "naga" }
],
"combat_value": 806,
"reward" : {
"value": 16000,
"resources":
{
"gems" : 16,
"gold" : 8000
}
}
},
{
"chance": 10,
"guards": [
{ "amount": 6, "type": "naga" },
{ "amount": 6, "type": "naga" },
{ "amount": 6, "type": "naga", "upgradeChance": 50 },
{ "amount": 6, "type": "naga" },
{ "amount": 6, "type": "naga" }
],
"combat_value": 1210,
"reward" : {
"value": 24000,
"resources":
{
"gems" : 24,
"gold" : 12000
}
}
}
]
},
"dragonflyHive" : {
"index" : 6,
"resetDuraition" : 28,
"name" : "Dragon Fly Hive",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 6, "type": "dragonFly" },
{ "amount": 6, "type": "dragonFly" },
{ "amount": 6, "type": "dragonFly" },
{ "amount": 6, "type": "dragonFly" },
{ "amount": 6, "type": "dragonFly" }
],
"combat_value": 154,
"reward" : {
"value": 3200,
"creatures": [ { "amount": 4, "type": "vyvern" } ]
}
},
{
"chance": 30,
"guards": [
{ "amount": 9, "type": "dragonFly" },
{ "amount": 9, "type": "dragonFly" },
{ "amount": 9, "type": "dragonFly" },
{ "amount": 9, "type": "dragonFly" },
{ "amount": 9, "type": "dragonFly" }
],
"combat_value": 230,
"reward" : {
"value": 4800,
"creatures": [ { "amount": 6, "type": "vyvern" } ]
}
},
{
"chance": 30,
"guards": [
{ "amount": 12, "type": "dragonFly" },
{ "amount": 12, "type": "dragonFly" },
{ "amount": 12, "type": "dragonFly" },
{ "amount": 12, "type": "dragonFly" },
{ "amount": 12, "type": "dragonFly" }
],
"combat_value": 307,
"reward" : {
"value": 6400,
"creatures": [ { "amount": 8, "type": "vyvern" } ]
}
},
{
"chance": 10,
"guards": [
{ "amount": 18, "type": "dragonFly" },
{ "amount": 18, "type": "dragonFly" },
{ "amount": 18, "type": "dragonFly" },
{ "amount": 18, "type": "dragonFly" },
{ "amount": 18, "type": "dragonFly" }
],
"combat_value": 461,
"reward" : {
"value": 9600,
"creatures": [ { "amount": 12, "type": "vyvern" } ]
}
}
]
}
}
},
"shipwreck" : {
"index" :85,
"handler": "bank",
"types" : {
"shipwreck" : {
"index" : 0,
"resetDuraition" : 28,
"name" : "Shipwreck",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 2, "type": "wight" },
{ "amount": 2, "type": "wight" },
{ "amount": 2, "type": "wight" },
{ "amount": 2, "type": "wight" },
{ "amount": 2, "type": "wight" }
],
"combat_value": 31,
"reward" : {
"value": 2000,
"resources":
{
"gold" : 2000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 3, "type": "wight" },
{ "amount": 3, "type": "wight" },
{ "amount": 3, "type": "wight" },
{ "amount": 3, "type": "wight" },
{ "amount": 3, "type": "wight" }
],
"combat_value": 46,
"reward" : {
"value": 3000,
"resources":
{
"gold" : 3000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 5, "type": "wight" },
{ "amount": 5, "type": "wight" },
{ "amount": 5, "type": "wight" },
{ "amount": 5, "type": "wight" },
{ "amount": 5, "type": "wight" }
],
"combat_value": 77,
"reward" : {
"value": 5000,
"resources":
{
"gold" : 4000
},
"artifacts": [ { "class" : "TREASURE" } ]
}
},
{
"chance": 10,
"guards": [
{ "amount": 10, "type": "wight" },
{ "amount": 10, "type": "wight" },
{ "amount": 10, "type": "wight" },
{ "amount": 10, "type": "wight" },
{ "amount": 10, "type": "wight" }
],
"combat_value": 154,
"reward" : {
"value": 7000,
"resources":
{
"gold" : 5000
},
"artifacts": [ { "class" : "MINOR" } ]
}
}
]
}
}
},
"derelictShip" : {
"index" :24,
"handler": "bank",
"types" : {
"derelictShip" : {
"index" : 0,
"resetDuraition" : 28,
"name" : "Derelict Ship",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 4, "type": "waterElemental" },
{ "amount": 4, "type": "waterElemental" },
{ "amount": 4, "type": "waterElemental" },
{ "amount": 4, "type": "waterElemental" },
{ "amount": 4, "type": "waterElemental" }
],
"combat_value": 138,
"reward" : {
"value": 3000,
"resources":
{
"gold" : 3000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 6, "type": "waterElemental" },
{ "amount": 6, "type": "waterElemental" },
{ "amount": 6, "type": "waterElemental" },
{ "amount": 6, "type": "waterElemental" },
{ "amount": 6, "type": "waterElemental" }
],
"combat_value": 207,
"reward" : {
"value": 4000,
"resources":
{
"gold" : 3000
},
"artifacts": [ { "class" : "TREASURE" } ]
}
},
{
"chance": 30,
"guards": [
{ "amount": 8, "type": "waterElemental" },
{ "amount": 8, "type": "waterElemental" },
{ "amount": 8, "type": "waterElemental" },
{ "amount": 8, "type": "waterElemental" },
{ "amount": 8, "type": "waterElemental" }
],
"combat_value": 276,
"reward" : {
"value": 5000,
"resources":
{
"gold" : 4000
},
"artifacts": [ { "class" : "TREASURE" } ]
}
},
{
"chance": 10,
"guards": [
{ "amount": 12, "type": "waterElemental" },
{ "amount": 12, "type": "waterElemental" },
{ "amount": 12, "type": "waterElemental" },
{ "amount": 12, "type": "waterElemental" },
{ "amount": 12, "type": "waterElemental" }
],
"combat_value": 414,
"reward" : {
"value": 8000,
"resources":
{
"gold" : 6000
},
"artifacts": [ { "class" : "MINOR" } ]
}
}
]
}
}
},
"crypt" : {
"index" :84,
"handler": "bank",
"types" : {
"crypt" : {
"index" : 0,
"resetDuraition" : 28,
"name" : "Crypt",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 10, "type": "skeleton" },
{ "amount": 10, "type": "walkingDead" },
{ "amount": 10, "type": "walkingDead" },
{ "amount": 10, "type": "skeleton" },
{ "amount": 10, "type": "skeleton" }
],
"combat_value": 75,
"reward" : {
"value": 1500,
"resources":
{
"gold" : 1500
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 13, "type": "skeleton" },
{ "amount": 10, "type": "walkingDead" },
{ "amount": 5, "type": "wight" },
{ "amount": 10, "type": "walkingDead" },
{ "amount": 12, "type": "skeleton" }
],
"combat_value": 94,
"reward" : {
"value": 2000,
"resources":
{
"gold" : 2000
}
}
},
{
"chance": 30,
"guards": [
{ "amount": 20, "type": "skeleton" },
{ "amount": 20, "type": "walkingDead" },
{ "amount": 10, "type": "wight" },
{ "amount": 5, "type": "vampire" }
],
"combat_value": 169,
"reward" : {
"value": 3500,
"resources":
{
"gold" : 2500
},
"artifacts": [ { "class" : "TREASURE" } ]
}
},
{
"chance": 10,
"guards": [
{ "amount": 20, "type": "skeleton" },
{ "amount": 20, "type": "walkingDead" },
{ "amount": 10, "type": "wight" },
{ "amount": 10, "type": "vampire" }
],
"combat_value": 225,
"reward" : {
"value": 6000,
"resources":
{
"gold" : 5000
},
"artifacts": [ { "class" : "TREASURE" } ]
}
}
]
}
}
},
"dragonUtopia" : {
"index" :25,
"handler": "bank",
"types" : {
"dragonUtopia" : {
"index" : 0,
"resetDuraition" : 28,
"name" : "Dragon Utopia",
"levels": [
{
"chance": 30,
"guards": [
{ "amount": 8, "type": "greenDragon" },
{ "amount": 5, "type": "redDragon" },
{ "amount": 2, "type": "goldDragon" },
{ "amount": 1, "type": "blackDragon" }
],
"combat_value": 769,
"reward" : {
"value": 38000,
"resources":
{
"gold" : 20000
},
"artifacts": [
{ "class" : "TREASURE" },
{ "class" : "MINOR" },
{ "class" : "MAJOR" },
{ "class" : "RELIC" }
]
}
},
{
"chance": 30,
"guards": [
{ "amount": 8, "type": "greenDragon" },
{ "amount": 6, "type": "redDragon" },
{ "amount": 3, "type": "goldDragon" },
{ "amount": 2, "type": "blackDragon" }
],
"combat_value": 209,
"reward" : {
"value": 57000,
"resources":
{
"gold" : 30000
},
"artifacts": [
{ "class" : "MINOR" },
{ "class" : "MAJOR" },
{ "class" : "RELIC" },
{ "class" : "RELIC" }
]
}
},
{
"chance": 30,
"guards": [
{ "amount": 8, "type": "greenDragon" },
{ "amount": 6, "type": "redDragon" },
{ "amount": 4, "type": "goldDragon" },
{ "amount": 3, "type": "blackDragon" }
],
"combat_value": 556,
"reward" : {
"value": 75000,
"resources":
{
"gold" : 40000
},
"artifacts": [
{ "class" : "MAJOR" },
{ "class" : "RELIC" },
{ "class" : "RELIC" },
{ "class" : "RELIC" }
]
}
},
{
"chance": 10,
"guards": [
{ "amount": 8, "type": "greenDragon" },
{ "amount": 7, "type": "redDragon" },
{ "amount": 6, "type": "goldDragon" },
{ "amount": 5, "type": "blackDragon" }
],
"combat_value": 343,
"reward" : {
"value": 90000,
"resources":
{
"gold" : 50000
},
"artifacts": [
{ "class" : "RELIC" },
{ "class" : "RELIC" },
{ "class" : "RELIC" },
{ "class" : "RELIC" }
]
}
}
]
}
}
},
"pyramid" : {
"index" :63,
"handler": "bank",
"types" : {
"pyramid" : {
"index" : 0,
"resetDuraition" : 28,
"name" : "Pyramid",
"levels": [
{
"chance": 100,
"guards": [
{ "amount": 20, "type": "goldGolem" },
{ "amount": 10, "type": "diamondGolem" },
{ "amount": 20, "type": "goldGolem" },
{ "amount": 10, "type": "diamondGolem" }
],
"combat_value": 786,
"reward" : {
"value": 15000,
"spells" : [ { "level" : 5 } ]
}
}
]
}
}
}
}

View File

@ -0,0 +1,126 @@
{
"creatureGeneratorCommon" : {
"index" :17,
"handler": "dwelling",
"base" : {
"base" : {
"visitableFrom" : [ "---", "+++", "+++" ],
"mask" : [ "VVV", "VBB", "VAA" ]
}
},
"types" : {
"basiliskPit" : { "index" : 0, "creatures" : [ [ "basilisk" ] ] },
"behemothCrag" : { "index" : 1, "creatures" : [ [ "behemoth" ] ], "guards" : true },
"pillarOfEyes" : { "index" : 2, "creatures" : [ [ "beholder" ] ] },
"hallOfDarkness" : { "index" : 3, "creatures" : [ [ "blackKnight" ] ], "guards" : true },
"dragonVault" : { "index" : 4, "creatures" : [ [ "boneDragon" ] ], "guards" : true },
"trainingGrounds" : { "index" : 5, "creatures" : [ [ "cavalier" ] ], "guards" : true },
"centaurStables" : { "index" : 6, "creatures" : [ [ "centaur" ] ] },
"airConflux" : { "index" : 7, "creatures" : [ [ "airElemental" ] ] },
"portalOfGlory" : { "index" : 8, "creatures" : [ [ "angel" ] ], "guards" : true },
"cyclopsCave" : { "index" : 9, "creatures" : [ [ "cyclop" ] ], "guards" : true },
"forsakenPalace" : { "index" : 10, "creatures" : [ [ "devil" ] ], "guards" : true },
"serpentFlyHive" : { "index" : 11, "creatures" : [ [ "serpentFly" ] ] },
"dwarfCottage" : { "index" : 12, "creatures" : [ [ "dwarf" ] ] },
"earthConflux" : { "index" : 13, "creatures" : [ [ "earthElemental" ] ], "guards" : true },
"fireLake" : { "index" : 14, "creatures" : [ [ "efreet" ] ], "guards" : true },
"homestead" : { "index" : 15, "creatures" : [ [ "woodElf" ] ] },
"fireConflux" : { "index" : 16, "creatures" : [ [ "fireElemental" ] ] },
"parapet" : { "index" : 17, "creatures" : [ [ "stoneGargoyle" ] ] },
"altarOfWishes" : { "index" : 18, "creatures" : [ [ "genie" ] ], "guards" : true },
"wolfPen" : { "index" : 19, "creatures" : [ [ "goblinWolfRider" ] ] },
"gnollHut" : { "index" : 20, "creatures" : [ [ "gnoll" ] ] },
"goblinBarracks" : { "index" : 21, "creatures" : [ [ "goblin" ] ] },
"hallOfSins" : { "index" : 22, "creatures" : [ [ "gog" ] ] },
"gorgonLair" : { "index" : 23, "creatures" : [ [ "gorgon" ] ], "guards" : true },
"dragonCliffs" : { "index" : 24, "creatures" : [ [ "greenDragon" ] ], "guards" : true },
"griffinTower" : { "index" : 25, "creatures" : [ [ "griffin" ] ] },
"harpyLoft" : { "index" : 26, "creatures" : [ [ "harpy" ] ] },
"kennels" : { "index" : 27, "creatures" : [ [ "hellHound" ] ] },
"hydraPond" : { "index" : 28, "creatures" : [ [ "hydra" ] ], "guards" : true },
"impCrucible" : { "index" : 29, "creatures" : [ [ "imp" ] ] },
"lizardDen" : { "index" : 30, "creatures" : [ [ "lizardman" ] ] },
"mageTower" : { "index" : 31, "creatures" : [ [ "mage" ] ] },
"manticoreLair" : { "index" : 32, "creatures" : [ [ "manticore" ] ], "guards" : true },
"medusaChapel" : { "index" : 33, "creatures" : [ [ "medusa" ] ] },
"labyrinth" : { "index" : 34, "creatures" : [ [ "minotaur" ] ], "guards" : true },
"monastery" : { "index" : 35, "creatures" : [ [ "monk" ] ], "guards" : true },
"goldenPavilion" : { "index" : 36, "creatures" : [ [ "naga" ] ], "guards" : true },
"demonGate" : { "index" : 37, "creatures" : [ [ "demon" ] ] },
"ogreFort" : { "index" : 38, "creatures" : [ [ "ogre" ] ] },
"orcTower" : { "index" : 39, "creatures" : [ [ "orc" ] ] },
"hellHole" : { "index" : 40, "creatures" : [ [ "pitFiend" ] ], "guards" : true },
"dragonCave" : { "index" : 41, "creatures" : [ [ "redDragon" ] ], "guards" : true },
"cliffNest" : { "index" : 42, "creatures" : [ [ "roc" ] ], "guards" : true },
"workshop" : { "index" : 43, "creatures" : [ [ "gremlin" ] ] },
"cloudTemple" : { "index" : 44, "creatures" : [ [ "giant" ] ], "guards" : true },
"dendroidArches" : { "index" : 45, "creatures" : [ [ "dendroidGuard" ] ], "guards" : true },
"warren" : { "index" : 46, "creatures" : [ [ "troglodyte" ] ] },
"waterConflux" : { "index" : 47, "creatures" : [ [ "waterElemental" ] ] },
"tombOfSouls" : { "index" : 48, "creatures" : [ [ "wight" ] ] },
"wyvernNest" : { "index" : 49, "creatures" : [ [ "wyvern" ] ], "guards" : true },
"enchantedSpring" : { "index" : 50, "creatures" : [ [ "pegasus" ] ] },
"unicornGladeBig" : { "index" : 51, "creatures" : [ [ "unicorn" ] ], "guards" : true },
"mausoleum" : { "index" : 52, "creatures" : [ [ "lich" ] ], "guards" : true },
"estate" : { "index" : 53, "creatures" : [ [ "vampire" ] ] },
"cursedTemple" : { "index" : 54, "creatures" : [ [ "skeleton" ] ] },
"graveyard" : { "index" : 55, "creatures" : [ [ "walkingDead" ] ] },
"guardhouse" : { "index" : 56, "creatures" : [ [ "pikeman" ] ] },
"archersTower" : { "index" : 57, "creatures" : [ [ "archer" ] ] },
"barracks" : { "index" : 58, "creatures" : [ [ "swordsman" ] ] },
"magicLantern" : { "index" : 59, "creatures" : [ [ "pixie" ] ] },
"altarOfThought" : { "index" : 60, "creatures" : [ [ "psychicElemental" ] ], "guards" : true },
"pyre" : { "index" : 61, "creatures" : [ [ "firebird" ] ], "guards" : true },
"frozenCliffs" : { "index" : 62, "creatures" : [ [ "azureDragon" ] ], "guards" : true },
"crystalCavern" : { "index" : 63, "creatures" : [ [ "crystalDragon" ] ], "guards" : true },
"magicForest" : { "index" : 64, "creatures" : [ [ "fairieDragon" ] ], "guards" : true },
"sulfurousLair" : { "index" : 65, "creatures" : [ [ "rustDragon" ] ], "guards" : true },
"enchantersHollow" : { "index" : 66, "creatures" : [ [ "enchanter" ] ], "guards" : true },
"treetopTower" : { "index" : 67, "creatures" : [ [ "sharpshooter" ] ], "guards" : true },
"unicornGlade" : { "index" : 68, "creatures" : [ [ "unicorn" ] ], "guards" : true },
"altarOfAir" : { "index" : 69, "creatures" : [ [ "airElemental" ] ] },
"altarOfEarth" : { "index" : 70, "creatures" : [ [ "earthElemental" ] ], "guards" : true },
"altarOfFire" : { "index" : 71, "creatures" : [ [ "fireElemental" ] ] },
"altarOfWater" : { "index" : 72, "creatures" : [ [ "waterElemental" ] ] },
"thatchedHut" : { "index" : 73, "creatures" : [ [ "halfling" ] ] },
"hovel" : { "index" : 74, "creatures" : [ [ "peasant" ] ] },
"boarGlen" : { "index" : 75, "creatures" : [ [ "boar" ] ] },
"tombOfCurses" : { "index" : 76, "creatures" : [ [ "mummy" ] ] },
"nomadTent" : { "index" : 77, "creatures" : [ [ "nomad" ] ] },
"rogueCavern" : { "index" : 78, "creatures" : [ [ "rogue" ] ] },
"trollBridge" : { "index" : 79, "creatures" : [ [ "troll" ] ], "guards" : true }
}
},
// subtype: unique special dwellings - golem factory and elemental conflux
"creatureGeneratorSpecial" : {
"index" :20,
"handler": "dwelling",
"types" : {
"elementalConflux" : {
"index" : 0,
"creatures" : [ // 4 separate "levels" to give them separate growth
[ "airElemental" ],
[ "waterElemental" ],
[ "fireElemental" ],
[ "earthElemental" ]
],
"guards" : [
{ "amount" : 12, "type" : "earthElemental" }
]
},
"golemFactory" : {
"index" : 1,
"creatures" : [ // 4 separate "levels" to give them separate growth
[ "ironGolem" ],
[ "stoneGolem" ],
[ "goldGolem" ],
[ "diamondGolem" ]
],
"guards" : [
{ "amount" : 9, "type" : "goldGolem" },
{ "amount" : 6, "type" : "diamondGolem" }
]
}
}
},
}

133
config/objects/generic.json Normal file
View File

@ -0,0 +1,133 @@
{
/// These are objects that can not be configured, either due to
/// their hardcoded status or because they don't have any configurable functionality
"prison" : {
"index" :62,
"handler": "prison",
"types" : {
"prison" : { "index" : 0 }
}
},
"altarOfSacrifice" : { "index" :2, "handler": "market" },
"tradingPost" : { "index" :221, "handler": "market" },
"tradingPostDUPLICATE" : { "index" :99, "handler": "market" },
"freelancersGuild" : { "index" :213, "handler": "market" },
"blackMarket" : { "index" :7, "handler": "blackMarket" },
"pandoraBox" : { "index" :6, "handler": "pandora" },
"event" : { "index" :26, "handler": "event" },
"redwoodObservatory" : { "index" :58, "handler": "observatory" },
"pillarOfFire" : { "index" :60, "handler": "observatory" },
"coverOfDarkness" : { "index" :15, "handler": "observatory" },
"subterraneanGate" : { "index" :103, "handler": "teleport" },
"whirlpool" : { "index" :111, "handler": "teleport" },
"refugeeCamp" : { "index" :78, "handler": "dwelling" },
"warMachineFactory" : { "index" :106, "handler": "dwelling" },
"shrineOfMagicLevel1" : { "index" :88, "handler": "shrine" },
"shrineOfMagicLevel2" : { "index" :89, "handler": "shrine" },
"shrineOfMagicLevel3" : { "index" :90, "handler": "shrine" },
"eyeOfTheMagi" : { "index" :27, "handler": "magi" },
"hutOfTheMagi" : { "index" :37, "handler": "magi" },
"lighthouse" : { "index" :42, "handler": "lighthouse" },
"magicWell" : { "index" :49, "handler": "magicWell" },
"obelisk" : { "index" :57, "handler": "obelisk" },
"oceanBottle" : { "index" :59, "handler": "sign" },
"scholar" : { "index" :81, "handler": "scholar" },
"shipyard" : { "index" :87, "handler": "shipyard" },
"sign" : { "index" :91, "handler": "sign" },
"sirens" : { "index" :92, "handler": "siren" },
"denOfThieves" : { "index" :97, "handler": "denOfThieves" },
"university" : { "index" :104, "handler": "university" },
"witchHut" : { "index" :113, "handler": "witch" },
"questGuard" : { "index" :215, "handler": "questGuard" },
/// Random objects
"randomResource" : { "index" :76, "handler": "resource" },
"randomTown" : { "index" :77, "handler": "town" },
"randomHero" : { "index" :70, "handler": "hero" },
"randomDwelling" : { "index" :216, "handler": "dwelling" },
"randomArtifact" : { "index" :65, "handler": "artifact" },
"randomArtifactTreasure" : { "index" :66, "handler": "artifact" },
"randomArtifactMinor" : { "index" :67, "handler": "artifact" },
"randomArtifactMajor" : { "index" :68, "handler": "artifact" },
"randomArtifactRelic" : { "index" :69, "handler": "artifact" },
"randomMonster" : { "index" :71, "handler": "monster" },
"randomMonsterLevel1" : { "index" :72, "handler": "monster" },
"randomMonsterLevel2" : { "index" :73, "handler": "monster" },
"randomMonsterLevel3" : { "index" :74, "handler": "monster" },
"randomMonsterLevel4" : { "index" :75, "handler": "monster" },
"randomMonsterLevel5" : { "index" :162, "handler": "monster" },
"randomMonsterLevel6" : { "index" :163, "handler": "monster" },
"randomMonsterLevel7" : { "index" :164, "handler": "monster" },
/// Classes without dedicated object
"hillFort" : { "index" :35, "handler": "generic" },
"grail" : { "index" :36, "handler": "generic" },
"tavern" : { "index" :95, "handler": "generic" },
"sanctuary" : { "index" :80, "handler": "generic" },
/// Passive objects, terrain overlays
"cursedGround" : { "index" :21, "handler": "generic" },
"magicPlains" : { "index" :46, "handler": "generic" },
"swampFoliage" : { "index" :211, "handler": "generic" },
"cloverField" : { "index" :222, "handler": "generic" },
"cursedGroundDUPLICATE" : { "index" :223, "handler": "generic" },
"evilFog" : { "index" :224, "handler": "generic" },
"favorableWinds" : { "index" :225, "handler": "generic" },
"fieryFields" : { "index" :226, "handler": "generic" },
"holyGround" : { "index" :227, "handler": "generic" },
"lucidPools" : { "index" :228, "handler": "generic" },
"magicClouds" : { "index" :229, "handler": "generic" },
"magicPlainsDUPLICATE" : { "index" :230, "handler": "generic" },
"rocklands" : { "index" :231, "handler": "generic" },
/// Decorations
"cactus" : { "index" :116, "handler": "static" },
"canyon" : { "index" :117, "handler": "static" },
"crater" : { "index" :118, "handler": "static" },
"deadVegetation" : { "index" :119, "handler": "static" },
"flowers" : { "index" :120, "handler": "static" },
"frozenLake" : { "index" :121, "handler": "static" },
"hole" : { "index" :124, "handler": "static" },
"kelp" : { "index" :125, "handler": "static" },
"lake" : { "index" :126, "handler": "static" },
"lavaFlow" : { "index" :127, "handler": "static" },
"lavaLake" : { "index" :128, "handler": "static" },
"mushrooms" : { "index" :129, "handler": "static" },
"log" : { "index" :130, "handler": "static" },
"mandrake" : { "index" :131, "handler": "static" },
"moss" : { "index" :132, "handler": "static" },
"mound" : { "index" :133, "handler": "static" },
"mountain" : { "index" :134, "handler": "static" },
"oakTrees" : { "index" :135, "handler": "static" },
"outcropping" : { "index" :136, "handler": "static" },
"pineTrees" : { "index" :137, "handler": "static" },
"riverDelta" : { "index" :143, "handler": "static" },
"rock" : { "index" :147, "handler": "static" },
"sandDune" : { "index" :148, "handler": "static" },
"sandPit" : { "index" :149, "handler": "static" },
"shrub" : { "index" :150, "handler": "static" },
"skull" : { "index" :151, "handler": "static" },
"stump" : { "index" :153, "handler": "static" },
"trees" : { "index" :155, "handler": "static" },
"volcano" : { "index" :158, "handler": "static" },
"reef" : { "index" :161, "handler": "static" },
"lakeDUPLICATE" : { "index" :177, "handler": "static" },
"treesDUPLICATE" : { "index" :199, "handler": "static" },
"desertHills" : { "index" :206, "handler": "static" },
"dirtHills" : { "index" :207, "handler": "static" },
"grassHills" : { "index" :208, "handler": "static" },
"roughHills" : { "index" :209, "handler": "static" },
"subterraneanRocks" : { "index" :210, "handler": "static" }
}

View File

@ -0,0 +1,208 @@
{
/// These are objects that have subtypes that change various aspects of their mechanics
/// Should be made configurable (either directly or via other parts of modding system ASAP)
/// Editing these objects either directly or via mod may have negative effect on game since they are handled by engine
// subtype: artifact ID
"artifact" : {
"index" :5,
"handler": "artifact",
"base" : {
"base" : {
"visitableFrom" : [ "+++", "+-+", "+++" ],
"mask" : [ "VV", "VA"]
}
}
},
// subtype: hero CLASS (not hero).
"hero" : {
"index" :34,
"handler": "hero",
"base" : {
"base" : {
"visitableFrom" : [ "+++", "+-+", "+++" ],
"mask" : [ "VV", "AV"]
}
}
},
// subtype: creatures
"monster" : {
"index" :54,
"handler": "monster",
"base" : {
"base" : {
"visitableFrom" : [ "+++", "+-+", "+++" ],
"mask" : [ "VV", "VA"]
}
}
},
// subtype: resource ID
"resource" : {
"index" :79,
"handler": "resource",
"base" : {
"base" : {
"visitableFrom" : [ "+++", "+-+", "+++" ],
"mask" : [ "VA" ]
}
},
"types" : {
"wood" : { "index" : 0, "templates" : { "res" : { "animation" : "AVTwood0.def" } } },
"mercury" : { "index" : 1, "templates" : { "res" : { "animation" : "AVTmerc0.def" } } },
"ore" : { "index" : 2, "templates" : { "res" : { "animation" : "AVTore0.def" } } },
"sulfur" : { "index" : 3, "templates" : { "res" : { "animation" : "AVTsulf0.def" } } },
"crystal" : { "index" : 4, "templates" : { "res" : { "animation" : "AVTcrys0.def" } } },
"gems" : { "index" : 5, "templates" : { "res" : { "animation" : "AVTgems0.def" } } },
"gold" : { "index" : 6, "templates" : { "res" : { "animation" : "AVTgold0.def" } } },
"mithril" : { "index" : 7 } // TODO: move to WoG?
}
},
// subtype: faction
"town" : {
"index" :98,
"handler": "town",
"base" : {
"filters" : {
// village image - fort not present
"village" : [ "noneOf", [ "fort" ] ],
// fort image - fort is here but not capitol
"fort" : [ "allOf", [ "fort" ], [ "noneOf", ["capitol" ] ] ],
// capitol image only when capitol is built
"capitol" : [ "capitol" ]
},
// "faction" : "stringID", // should be set by engine
"base" : {
"visitableFrom" : [ "---", "+++", "+++" ],
"mask" : [
"VVVVVV", // a LOT of just visible rows due to towns like Tower
"VVVVVV",
"VVVVVV",
"VVBBBV",
"VBBBBB",
"VBBABB"
]
}
}
},
// subtype: one of 3 possible boats
"boat" : {
"index" :8,
"handler": "boat",
"base" : {
"base" : {
"visitableFrom" : [ "+++", "+-+", "+++" ],
"mask" : [ "VVV", "VAV" ]
}
},
"types" : {
"evil" : { "index" : 0 },
"good" : { "index" : 1 },
"neutral" : { "index" : 2 },
}
},
// subtype: color of guard
"borderGuard" : {
"index" :9,
"handler": "borderGuard",
"types" : {
"lblue" : { "index" : 0 },
"green" : { "index" : 1 },
"red" : { "index" : 2 },
"dblue" : { "index" : 3 },
"brown" : { "index" : 4 },
"purple" : { "index" : 5 },
"white" : { "index" : 6 },
"black" : { "index" : 7 }
}
},
"borderGate" : {
"index" :212,
"handler": "borderGate",
"types" : {
"lblue" : { "index" : 0 },
"green" : { "index" : 1 },
"red" : { "index" : 2 },
"dblue" : { "index" : 3 },
"brown" : { "index" : 4 },
"purple" : { "index" : 5 },
"white" : { "index" : 6 },
"black" : { "index" : 7 }
}
},
"keymasterTent" : {
"index" :10,
"handler": "keymaster",
"types" : {
"lblue" : { "index" : 0 },
"green" : { "index" : 1 },
"red" : { "index" : 2 },
"dblue" : { "index" : 3 },
"brown" : { "index" : 4 },
"purple" : { "index" : 5 },
"white" : { "index" : 6 },
"black" : { "index" : 7 }
}
},
// subtype: different revealed areas
"cartographer" : {
"index" :13,
"handler": "cartographer",
"types" : {
"water" : { "index" : 0 },
"land" : { "index" : 1 },
"subterra" : { "index" : 2 }
}
},
// subtype: resource ID
"mine" : {
"index" :53,
"handler": "mine",
"types" : {
"sawmill" : { "index" : 0 },
"alchemistLab" : { "index" : 1 },
"orePit" : { "index" : 2 },
"sulfurDune" : { "index" : 3 },
"crystalCavern" : { "index" : 4 },
"gemPond" : { "index" : 5 },
"goldMine" : { "index" : 6 },
}
},
"abandonedMine" : {
"index" :220,
"handler": "mine",
"types" : {
"mine" : { "index" : 7 }
}
},
// subtype: 0 = normal, 1 = anti-magic
"garrisonHorizontal" : { "index" :33, "handler": "garrison" },
"garrisonVertical" : { "index" :219, "handler": "garrison" },
// Subtype: paired monoliths
"monolithOneWayEntrance" : { "index" :43, "handler": "teleport" },
"monolithOneWayExit" : { "index" :44, "handler": "teleport" },
"monolithTwoWay" : { "index" :45, "handler": "teleport" },
// subtype: different appearance. That's all?
"seerHut" : { "index" :83, "handler": "seerHut" },
// subtype: level
"randomDwellingLvl" : { "index" :217, "handler": "dwelling" },
// subtype: faction ID
"randomDwellingFaction" : { "index" :218, "handler": "dwelling" },
// don't have subtypes (at least now), but closely connected to this objects
"spellScroll" : { "index" :93, "handler": "artifact" },
"heroPlaceholder" : { "index" :214, "handler": "heroPlaceholder" }
}

View File

@ -0,0 +1,44 @@
{
/// These are objects that covered by concept of "configurable object"
/// Most or even all of their configuration located in this file
"magicSpring" : { "index" :48, "handler": "magicSpring" },
"mysticalGarden" : { "index" :55, "handler": "oncePerWeek" },
"windmill" : { "index" :112, "handler": "oncePerWeek" },
"waterWheel" : { "index" :109, "handler": "oncePerWeek" },
"leanTo" : { "index" :39, "handler": "onceVisitable" },
"corpse" : { "index" :22, "handler": "onceVisitable" },
"wagon" : { "index" :105, "handler": "onceVisitable" },
"warriorTomb" : { "index" :108, "handler": "onceVisitable" },
"campfire" : { "index" :12, "handler": "pickable" },
"flotsam" : { "index" :29, "handler": "pickable" },
"seaChest" : { "index" :82, "handler": "pickable" },
"shipwreckSurvivor" : { "index" :86, "handler": "pickable" },
"treasureChest" : { "index" :101, "handler": "pickable" },
"arena" : { "index" :4, "handler": "oncePerHero" },
"marlettoTower" : { "index" :23, "handler": "oncePerHero" },
"gardenOfRevelation" : { "index" :32, "handler": "oncePerHero" },
"libraryOfEnlightenment" : { "index" :41, "handler": "oncePerHero" },
"mercenaryCamp" : { "index" :51, "handler": "oncePerHero" },
"starAxis" : { "index" :61, "handler": "oncePerHero" },
"learningStone" : { "index" :100, "handler": "oncePerHero" },
"treeOfKnowledge" : { "index" :102, "handler": "oncePerHero" },
"schoolOfMagic" : { "index" :47, "handler": "oncePerHero" },
"schoolOfWar" : { "index" :107, "handler": "oncePerHero" },
"buoy" : { "index" :11, "handler": "bonusingObject" },
"swanPond" : { "index" :14, "handler": "bonusingObject" },
"faerieRing" : { "index" :28, "handler": "bonusingObject" },
"fountainOfFortune" : { "index" :30, "handler": "bonusingObject" },
"fountainOfYouth" : { "index" :31, "handler": "bonusingObject" },
"idolOfFortune" : { "index" :38, "handler": "bonusingObject" },
"mermaids" : { "index" :52, "handler": "bonusingObject" },
"oasis" : { "index" :56, "handler": "bonusingObject" },
"stables" : { "index" :94, "handler": "bonusingObject" },
"temple" : { "index" :96, "handler": "bonusingObject" },
"rallyFlag" : { "index" :64, "handler": "bonusingObject" },
"wateringHole" : { "index" :110, "handler": "bonusingObject" },
}

View File

@ -9,26 +9,48 @@
"1" :
{
"type" : "playerStart", "size" : 1, "owner" : 1,
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
"monsters" : "normal",
"mines" : {"wood" : 1, "ore" : 1, "gems" : 1, "crystal" : 1, "sulfur" : 1, "mercury" : 1},
"treasure" : [
{"min" : 2100, "max": 3000, "density" : 5},
{"min" : 300, "max": 1500, "density" : 10}
]
},
"2" :
{
"type" : "playerStart", "size" : 1, "owner" : 2,
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
"monsters" : "normal",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"3" :
{
"type" : "playerStart", "size" : 1, "owner" : 3,
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
"monsters" : "normal",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"4" :
{
"type" : "playerStart", "size" : 1, "owner" : 4,
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true
"playerTowns" : { "castles" : 1 }, "neutralTowns" : { "towns" : 1 }, "townsAreSameType" : true,
"monsters" : "normal",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"5" :
{
"type" : "treasure", "size" : 2, "terrainTypes" : [ "sand" ], "neutralTowns" : { "castles" : 1 }
"type" : "treasure", "size" : 2, "terrainTypes" : [ "sand" ], "matchTerrainToTown" : false,
"neutralTowns" : { "castles" : 1 },
"monsters" : "strong",
"mines" : {"gold" : 2},
"treasure" : [
{"min" : 9000, "max": 10000, "density" : 3},
{"min" : 6000, "max": 10000, "density" : 15}
]
}
},
"connections" :
@ -48,34 +70,58 @@
"1" :
{
"type" : "playerStart", "size" : 1, "owner" : 1,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
"mines" : {"wood" : 1, "ore" : 1},
"treasure" : [
{"min" : 400, "max": 1500, "density" : 16},
{"min" : 1500, "max": 2500, "density" : 4}
]
},
"2" :
{
"type" : "playerStart", "size" : 1, "owner" : 2,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"3" :
{
"type" : "treasure", "size" : 2, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : "1"
"type" : "treasure", "size" : 2, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : 1,
"monsters" : "weak",
"mines" : {"gems" : 1, "crystal" : 1, "sulfur" : 1, "mercury" : 1, "gold" : 1},
"treasure" : [
{"min" : 2000, "max": 4000, "density" : 15},
{"min" : 4000, "max": 5000, "density" : 5}
]
},
"4" :
{
"type" : "treasure", "size" : 2, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : "2"
"type" : "treasure", "size" : 2, "neutralTowns" : { "towns" : 1 }, "townTypeLikeZone" : 2,
"monsters" : "weak",
"minesLikeZone" : 3,
"treasureLikeZone" : 3
},
"5" :
{
"type" : "treasure", "size" : 3, "neutralTowns" : { "castles" : 1 }, "terrainTypes" : [ "sand" ]
"type" : "treasure", "size" : 3, "neutralTowns" : { "castles" : 1 }, "terrainTypes" : [ "sand" ],
"monsters" : "strong",
"mines" : {"gold" : 2},
"treasure" : [
{"min" : 11000, "max": 12000, "density" : 5},
{"min" : 6000, "max": 11000, "density" : 10}
]
}
},
"connections" :
[
{ "a" : "1", "b" : "3", "guard" : 1000 },
{ "a" : "1", "b" : "5", "guard" : 4000 },
{ "a" : "2", "b" : "4", "guard" : 1000 },
{ "a" : "2", "b" : "5", "guard" : 4000 },
{ "a" : "3", "b" : "5", "guard" : 2000 },
{ "a" : "4", "b" : "5", "guard" : 2000 }
{ "a" : "1", "b" : "3", "guard" : 3000 },
{ "a" : "1", "b" : "5", "guard" : 9000 },
{ "a" : "2", "b" : "4", "guard" : 3000 },
{ "a" : "2", "b" : "5", "guard" : 9000 },
{ "a" : "3", "b" : "5", "guard" : 6000 },
{ "a" : "4", "b" : "5", "guard" : 6000 }
]
},
"Golden Ring" :
@ -87,36 +133,63 @@
"1" :
{
"type" : "playerStart", "size" : 3, "owner" : 1,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
"mines" : {"wood" : 1, "ore" : 1},
"treasure" : [
{"min" : 300, "max": 2000, "density": 15},
{"min" : 2100, "max": 2500, "density": 5}
]
},
"2" :
{
"type" : "playerStart", "size" : 3, "owner" : 2,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"3" :
{
"type" : "playerStart", "size" : 3, "owner" : 3,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"4" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "1" },
"5" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "1" },
"6" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "2" },
"7" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "2" },
"8" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "3" },
"9" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "3" },
"10" : { "type" : "treasure", "size" : 1, "neutralTowns" : { "towns" : 1 } },
"11" : { "type" : "treasure", "size" : 1, "neutralTowns" : { "towns" : 1 } },
"12" : { "type" : "treasure", "size" : 1, "neutralTowns" : { "towns" : 1 } }
"4" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : 1,
"monsters" : "normal",
"mines" : {"gems" : 1, "crystal" : 1},
"treasure" : [
{"min" : 3000, "max": 10000, "density" : 12},
{"min" : 6000, "max": 10000, "density" : 6}
]},
"5" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : 1,
"monsters" : "normal",
"mines" : {"sulfur" : 1, "mercury" : 1},
"treasureLikeZone" : 4},
"6" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : 2, "monsters" : "normal", "minesLikeZone" : 5, "treasureLikeZone" : 4 },
"7" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : 2, "monsters" : "normal", "minesLikeZone" : 4, "treasureLikeZone" : 4 },
"8" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : 3, "monsters" : "normal", "minesLikeZone" : 4, "treasureLikeZone" : 4 },
"9" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : 3, "monsters" : "normal", "minesLikeZone" : 5, "treasureLikeZone" : 4 },
"10" : { "type" : "treasure", "size" : 1, "neutralTowns" : { "towns" : 1 },
"monsters" : "strong",
"mines" : {"gold" : 1},
"treasure" : [
{"min" : 21000, "max": 25000, "density" : 3},
{"min" : 10000, "max": 21000, "density" : 10}
]},
"11" : { "type" : "treasure", "size" : 1, "neutralTowns" : { "towns" : 1 }, "monsters" : "strong", "minesLikeZone" : 10, "treasureLikeZone" : 10 },
"12" : { "type" : "treasure", "size" : 1, "neutralTowns" : { "towns" : 1 }, "monsters" : "strong", "minesLikeZone" : 10, "treasureLikeZone" : 10 }
},
"connections" :
[
{ "a" : "1", "b" : "4", "guard" : 2000 },
{ "a" : "1", "b" : "5", "guard" : 2000 },
{ "a" : "2", "b" : "6", "guard" : 2000 },
{ "a" : "2", "b" : "7", "guard" : 2000 },
{ "a" : "3", "b" : "8", "guard" : 2000 },
{ "a" : "3", "b" : "9", "guard" : 2000 },
{ "a" : "1", "b" : "4", "guard" : 2500 },
{ "a" : "1", "b" : "5", "guard" : 2500 },
{ "a" : "2", "b" : "6", "guard" : 2500 },
{ "a" : "2", "b" : "7", "guard" : 2500 },
{ "a" : "3", "b" : "8", "guard" : 2500 },
{ "a" : "3", "b" : "9", "guard" : 2500 },
{ "a" : "4", "b" : "10", "guard" : 20000 },
{ "a" : "5", "b" : "12", "guard" : 20000 },
{ "a" : "6", "b" : "10", "guard" : 20000 },
@ -134,25 +207,29 @@
"1" :
{
"type" : "playerStart", "size" : 2, "owner" : 1,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
},
"2" :
{
"type" : "playerStart", "size" : 2, "owner" : 2,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "normal",
},
"3" :
{
"type" : "cpuStart", "size" : 3, "owner" : 3,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "weak",
},
"4" :
{
"type" : "cpuStart", "size" : 3, "owner" : 4,
"playerTowns" : { "castles" : 1 }
"playerTowns" : { "castles" : 1 },
"monsters" : "weak",
},
"5" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "3" },
"6" : { "type" : "treasure", "size" : 1, "terrainTypeLikeZone" : "4" }
"5" : { "type" : "treasure", "size" : 1, "monsters" : "strong", "terrainTypeLikeZone" : 3 },
"6" : { "type" : "treasure", "size" : 1, "monsters" : "strong", "terrainTypeLikeZone" : 4 }
},
"connections" :
[
@ -163,5 +240,73 @@
{ "a" : "3", "b" : "5", "guard" : 2000 },
{ "a" : "4", "b" : "6", "guard" : 2000 }
]
},
"Jebus Cross":
{
"minSize" : "l", "maxSize" : "xl",
"players" : "4",
"zones":
{
"1":
{
"type" : "playerStart", "size" : 30, "owner" : 1,
"playerTowns" : { "castles" : 1 },
"neutralTowns" : { "towns" : 2 },
"monsters" : "weak",
"mines" : {"wood" : 4, "ore" : 4, "gems" : 1, "crystal" : 1, "sulfur" : 1, "mercury" : 1, "gold" : 2},
"treasure" : [
{"min" : 12000, "max": 22000, "density": 1},
{"min" : 500, "max": 1600, "density": 6},
{"min" : 300, "max": 3000, "density": 14}
]
},
"2":
{
"type" : "playerStart", "size" : 30, "owner" : 2,
"playerTowns" : { "castles" : 1 },
"neutralTowns" : { "towns" : 2 },
"monsters" : "weak",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"3":
{
"type" : "playerStart", "size" : 30, "owner" : 3,
"playerTowns" : { "castles" : 1 },
"neutralTowns" : { "towns" : 2 },
"monsters" : "weak",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"4":
{
"type" : "playerStart", "size" : 30, "owner" : 4,
"playerTowns" : { "castles" : 1 },
"neutralTowns" : { "towns" : 2 },
"monsters" : "weak",
"minesLikeZone" : 1,
"treasureLikeZone" : 1
},
"5" :
{
"type" : "treasure", "size" : 40,
"neutralTowns" : { "castles" : 2 },
"terrainTypes" : [ "sand" ], "matchTerrainToTown" : false,
"monsters" : "strong",
"mines" : {"gold" : 4},
"treasure" : [
{"min" : 35000, "max": 55000, "density" : 3},
{"min" : 25000, "max": 35000, "density" : 10},
{"min" : 10000, "max": 25000, "density" : 10}
]
}
},
"connections" :
[
{ "a" : "1", "b" : "5", "guard" : 45000 },
{ "a" : "2", "b" : "5", "guard" : 45000 },
{ "a" : "3", "b" : "5", "guard" : 45000 },
{ "a" : "4", "b" : "5", "guard" : 45000 }
]
}
}

View File

@ -104,46 +104,16 @@
"type":"object",
"additionalProperties" : false,
"required" : [
"adventureMap", "buildingsIcons", "buildings", "creatures", "guildWindow", "names",
"mapObject", "buildingsIcons", "buildings", "creatures", "guildWindow", "names",
"hallBackground", "hallSlots", "horde", "mageGuild", "moatDamage", "defaultTavern", "tavernVideo", "guildBackground", "musicTheme", "siege", "structures", "townBackground", "warMachine"
],
"description": "town",
"properties":{
"adventureMap": {
"type":"object",
"additionalProperties" : false,
"description": "Paths to images of object on adventure map",
"required" : [ "capitol", "castle", "village" ],
"properties":{
"capitol": {
"type":"string",
"description": "Town with capitol",
"format" : "defFile"
},
"castle": {
"type":"string",
"description": "Town with built fort",
"format" : "defFile"
},
"village": {
"type":"string",
"description": "Village without built fort",
"format" : "defFile"
},
"dwellings" : {
"type" : "array",
"minItems" : 7,
"maxItems" : 7,
"description" : "Dwellings on adventure map",
"items" : {
"type" : "object",
"additionalProperties" : false,
"required" : [ "name", "graphics" ],
"properties" : {
"name": { "type":"string" },
"graphics": { "type":"string", "format" : "defFile" }
}
}
"mapObject" : {
"properties" : {
"filters" : {
"type" : "object",
"additionalProperties" : { "type" : "array" }
}
}
},

View File

@ -6,7 +6,7 @@
"required" : [
"animation", "faction", "highLevelChance", "lowLevelChance",
"name", "primarySkills", "secondarySkills", "tavern", "defaultTavern",
"affinity", "commander"
"affinity", "commander", "mapObject"
],
"additionalProperties" : false,
@ -15,7 +15,7 @@
"type":"object",
"additionalProperties" : false,
"description": "Files related to hero animation",
"required": [ "battle", "map" ],
"required": [ "battle" ],
"properties":{
"battle": {
"type":"object",
@ -34,24 +34,14 @@
"format" : "defFile"
}
}
},
"map": {
"type":"object",
"additionalProperties" : false,
"description": "Hero animations for adventure map",
"required": [ "female", "male" ],
"properties":{
"female": {
"type":"string",
"description": "Female version. Warning: not implemented!",
"format" : "defFile"
},
"male": {
"type":"string",
"description": "Male version",
"format" : "defFile"
}
}
}
}
},
"mapObject" : {
"properties" : {
"filters" : {
"type" : "object",
"additionalProperties" : { "type" : "array" }
}
}
},

View File

@ -0,0 +1,31 @@
{
"type":"object",
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI map object format",
"description" : "Description of map object class",
"required": [ "handler", "name" ],
"additionalProperties" : false,
"properties":{
"index": {
"type":"number",
},
"name": {
"type":"string",
},
"handler": {
"type":"string",
},
"base": {
"type" : "object"
},
"types": {
"type":"object",
"additionalProperties": {
"$ref" : "vcmi:objectType"
}
}
}
}

View File

@ -3,18 +3,10 @@
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI map object template format",
"description" : "Description of map object tempate that describes appearence of object instance",
"required": ["basebase", "base", "animation", "mask" ],
"required": [ "animation", "mask" ],
"additionalProperties" : false,
"properties":{
"basebase": {
"type" : "number",
"description": "Base object type, e.g. town or hero"
},
"base": {
"type" : "number",
"description": "Object subtype, e.g. Castle, Rampart, Cleric, Demon"
},
"animation": {
"type" : "string",
"description": "Path to def file with animation of this object",

View File

@ -0,0 +1,27 @@
{
"type":"object",
"$schema": "http://json-schema.org/draft-04/schema",
"title" : "VCMI map object type format",
"description" : "Description of map object type, used only as sub-schema of object",
"required": [ ],
"additionalProperties" : true, // may have type-dependant properties
"properties":{
"index": {
"type":"number",
},
"name": {
"type":"string",
},
"base": {
"type" : "object"
},
"templates": {
"type":"object",
"additionalProperties": {
"$ref" : "vcmi:objectTemplate"
}
}
}
}

View File

@ -13,7 +13,7 @@
#include <numeric>
#include "VCMI_Lib.h"
#include "CObjectHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "CHeroHandler.h"
#include "CCreatureHandler.h"
#include "CSpellHandler.h"

View File

@ -4,12 +4,14 @@
#include "BattleHex.h"
#include "HeroBonus.h"
#include "CCreatureSet.h"
#include "CObjectHandler.h"
#include "mapObjects/CGTownInstance.h"
#include "mapObjects/CGHeroInstance.h"
#include "CCreatureHandler.h"
#include "CObstacleInstance.h"
#include "ConstTransitivePtr.h"
#include "GameConstants.h"
#include "CBattleCallback.h"
#include "int3.h"
/*
* BattleState.h, part of VCMI engine

View File

@ -16,11 +16,13 @@
#include "VCMI_Lib.h"
#include "CModHandler.h"
#include "CSpellHandler.h"
#include "CObjectHandler.h"
#include "mapObjects/MapObjects.h"
#include "NetPacksBase.h"
#include "GameConstants.h"
#include "CRandomGenerator.h"
#include "mapObjects/CObjectClassesHandler.h"
using namespace boost::assign;
// Note: list must match entries in ArtTraits.txt
@ -260,12 +262,21 @@ CArtifact * CArtHandler::loadFromJson(const JsonNode & node)
return art;
}
void CArtHandler::addSlot(CArtifact * art, const std::string & slotID)
ArtifactPosition CArtHandler::stringToSlot(std::string slotName)
{
#define ART_POS(x) ( #x, ArtifactPosition::x )
static const std::map<std::string, ArtifactPosition> artifactPositionMap = boost::assign::map_list_of ART_POS_LIST;
#undef ART_POS
auto it = artifactPositionMap.find (slotName);
if (it != artifactPositionMap.end())
return it->second;
logGlobal->warnStream() << "Warning! Artifact slot " << slotName << " not recognized!";
return ArtifactPosition::PRE_FIRST;
}
void CArtHandler::addSlot(CArtifact * art, const std::string & slotID)
{
if (slotID == "MISC")
{
art->possibleSlots[ArtBearer::HERO] += ArtifactPosition::MISC1, ArtifactPosition::MISC2, ArtifactPosition::MISC3, ArtifactPosition::MISC4, ArtifactPosition::MISC5;
@ -276,14 +287,9 @@ void CArtHandler::addSlot(CArtifact * art, const std::string & slotID)
}
else
{
auto it = artifactPositionMap.find (slotID);
if (it != artifactPositionMap.end())
{
auto slot = it->second;
auto slot = stringToSlot(slotID);
if (slot != ArtifactPosition::PRE_FIRST)
art->possibleSlots[ArtBearer::HERO].push_back (slot);
}
else
logGlobal->warnStream() << "Warning! Artifact slot " << slotID << " not recognized!";
}
}
@ -301,7 +307,7 @@ void CArtHandler::loadSlots(CArtifact * art, const JsonNode & node)
}
}
void CArtHandler::loadClass(CArtifact * art, const JsonNode & node)
CArtifact::EartClass CArtHandler::stringToClass(std::string className)
{
static const std::map<std::string, CArtifact::EartClass> artifactClassMap = boost::assign::map_list_of
("TREASURE", CArtifact::ART_TREASURE)
@ -310,16 +316,17 @@ void CArtHandler::loadClass(CArtifact * art, const JsonNode & node)
("RELIC", CArtifact::ART_RELIC)
("SPECIAL", CArtifact::ART_SPECIAL);
auto it = artifactClassMap.find (node["class"].String());
auto it = artifactClassMap.find (className);
if (it != artifactClassMap.end())
{
art->aClass = it->second;
}
else
{
logGlobal->warnStream() << "Warning! Artifact rarity " << node["class"].String() << " not recognized!";
art->aClass = CArtifact::ART_SPECIAL;
}
return it->second;
logGlobal->warnStream() << "Warning! Artifact rarity " << className << " not recognized!";
return CArtifact::ART_SPECIAL;
}
void CArtHandler::loadClass(CArtifact * art, const JsonNode & node)
{
art->aClass = stringToClass(node["class"].String());
}
void CArtHandler::loadType(CArtifact * art, const JsonNode & node)
@ -422,7 +429,7 @@ CreatureID CArtHandler::machineIDToCreature(ArtifactID id)
return CreatureID::NONE; //this artifact is not a creature
}
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts)
{
auto getAllowedArts = [&](std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, CArtifact::EartClass flag)
{
@ -431,8 +438,11 @@ ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
for (auto & arts_i : *arts)
{
CArtifact *art = arts_i;
out.push_back(art);
if (accepts(arts_i->id))
{
CArtifact *art = arts_i;
out.push_back(art);
}
}
};
@ -467,6 +477,16 @@ ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
return artID;
}
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts)
{
return pickRandomArtifact(rand, 0xff, accepts);
}
ArtifactID CArtHandler::pickRandomArtifact(CRandomGenerator & rand, int flags)
{
return pickRandomArtifact(rand, flags, [](ArtifactID){ return true;});
}
Bonus *createBonus(Bonus::BonusType type, int val, int subtype, Bonus::ValueType valType, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalInfo = 0)
{
auto added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
@ -647,20 +667,22 @@ void CArtHandler::afterLoadFinalization()
}
}
//Note: "10" is used here because H3 text files don't define any template for art with ID 0
ObjectTemplate base = VLC->dobjinfo->pickCandidates(Obj::ARTIFACT, 10).front();
for (CArtifact * art : artifacts)
{
VLC->objtypeh->loadSubObject(art->Name(), JsonNode(), Obj::ARTIFACT, art->id.num);
if (!art->advMapDef.empty())
{
base.animationFile = art->advMapDef;
base.subid = art->id;
JsonNode templ;
templ["animation"].String() = art->advMapDef;
// replace existing (if any) and add new template.
// add new template.
// Necessary for objects added via mods that don't have any templates in H3
VLC->dobjinfo->eraseAll(Obj::ARTIFACT, art->id);
VLC->dobjinfo->registerTemplate(base);
VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->addTemplate(templ);
}
// object does not have any templates - this is not usable object (e.g. pseudo-art like lock)
if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->getTemplates().empty())
VLC->objtypeh->removeSubObject(Obj::ARTIFACT, art->id);
}
}

View File

@ -203,11 +203,17 @@ public:
boost::optional<std::vector<CArtifact*>&> listFromClass(CArtifact::EartClass artifactClass);
ArtifactPosition stringToSlot(std::string slotName);
CArtifact::EartClass stringToClass(std::string className);
/// Gets a artifact ID randomly and removes the selected artifact from this handler.
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags);
ArtifactID pickRandomArtifact(CRandomGenerator & rand, std::function<bool(ArtifactID)> accepts);
ArtifactID pickRandomArtifact(CRandomGenerator & rand, int flags, std::function<bool(ArtifactID)> accepts);
bool legalArtifact(ArtifactID id);
void getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, int flag);
void getAllowed(std::vector<ConstTransitivePtr<CArtifact> > &out, int flags);
//void getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, int flag);
//void getAllowed(std::vector<ConstTransitivePtr<CArtifact> > &out, int flags);
bool isBigArtifact (ArtifactID artID) const {return bigArtifacts.find(artID) != bigArtifacts.end();}
void initAllowedArtifactsList(const std::vector<bool> &allowed); //allowed[art_id] -> 0 if not allowed, 1 if allowed
static ArtifactID creatureToMachineID(CreatureID id);

View File

@ -9,6 +9,8 @@
#include "CModHandler.h"
#include "StringConstants.h"
#include "mapObjects/CObjectClassesHandler.h"
using namespace boost::assign;
/*
@ -1114,19 +1116,19 @@ void CCreatureHandler::buildBonusTreeForTiers()
void CCreatureHandler::afterLoadFinalization()
{
ObjectTemplate base = VLC->dobjinfo->pickCandidates(Obj::MONSTER, 0).front();
for (CCreature * crea : creatures)
{
VLC->objtypeh->loadSubObject(crea->nameSing, JsonNode(), Obj::MONSTER, crea->idNumber.num);
if (!crea->advMapDef.empty())
{
base.animationFile = crea->advMapDef;
base.subid = crea->idNumber;
// replace existing (if any) and add new template.
// Necessary for objects added via mods that don't have any templates in H3
VLC->dobjinfo->eraseAll(Obj::MONSTER, crea->idNumber);
VLC->dobjinfo->registerTemplate(base);
JsonNode templ;
templ["animation"].String() = crea->advMapDef;
VLC->objtypeh->getHandlerFor(Obj::MONSTER, crea->idNumber)->addTemplate(templ);
}
// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower)
if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, crea->idNumber.num)->getTemplates().empty())
VLC->objtypeh->removeSubObject(Obj::MONSTER, crea->idNumber.num);
}
}

View File

@ -4,7 +4,7 @@
#include "CCreatureHandler.h"
#include "VCMI_Lib.h"
#include "CModHandler.h"
#include "CObjectHandler.h"
#include "mapObjects/CGHeroInstance.h"
#include "IGameCallback.h"
#include "CGameState.h"
#include "CGeneralTextHandler.h"

View File

@ -12,7 +12,7 @@
#include "CGameInfoCallback.h"
#include "CGameState.h" // PlayerState
#include "CObjectHandler.h" // for CGObjectInstance
#include "mapObjects/CObjectHandler.h" // for CGObjectInstance
#include "StartInfo.h" // for StartInfo
#include "BattleState.h" // for BattleInfo
#include "NetPacks.h" // for InfoWindow

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,6 @@
#include "IGameCallback.h"
#include "ResourceSet.h"
#include "int3.h"
#include "CObjectHandler.h"
#include "CRandomGenerator.h"
/*
@ -167,6 +166,7 @@ public:
ObjectInstanceID currentSelection; //id of hero/town, 0xffffffff if none
TeamID team;
TResources resources;
std::set<ObjectInstanceID> visitedObjects; // as a std::set, since most accesses here will be from visited status checks
std::vector<ConstTransitivePtr<CGHeroInstance> > heroes;
std::vector<ConstTransitivePtr<CGTownInstance> > towns;
std::vector<ConstTransitivePtr<CGHeroInstance> > availableHeroes; //heroes available in taverns
@ -183,7 +183,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & color & human & currentSelection & team & resources & status;
h & heroes & towns & availableHeroes & dwellings;
h & heroes & towns & availableHeroes & dwellings & visitedObjects;
h & getBonusList(); //FIXME FIXME FIXME
h & status & daysWithoutCastle;
h & enteredLosingCheatCode & enteredWinningCheatCode;

View File

@ -290,7 +290,6 @@ CGeneralTextHandler::CGeneralTextHandler()
readToVector("DATA/HEROSCRN.TXT", heroscrn);
readToVector("DATA/TENTCOLR.TXT", tentColors);
readToVector("DATA/SKILLLEV.TXT", levels);
readToVector("DATA/OBJNAMES.TXT", names);
localizedTexts = JsonNode(ResourceID("config/translate.json", EResType::TEXT));

View File

@ -112,7 +112,6 @@ public:
std::vector<std::string> victoryConditions;
//objects
std::vector<std::string> names; //vector of objects; i-th object in vector has subnumber i
std::vector<std::string> creGens; //names of creatures' generators
std::vector<std::string> creGens4; //names of multiple creatures' generators
std::vector<std::string> advobtxt;

View File

@ -10,9 +10,11 @@
#include "CCreatureHandler.h"
#include "CModHandler.h"
#include "CTownHandler.h"
#include "CObjectHandler.h" //for hero specialty
#include "mapObjects/CObjectHandler.h" //for hero specialty
#include <math.h>
#include "mapObjects/CObjectClassesHandler.h"
/*
* CHeroHandler.cpp, part of VCMI engine
*
@ -102,13 +104,12 @@ CHeroClass *CHeroClassHandler::loadFromJson(const JsonNode & node)
heroClass->imageBattleFemale = node["animation"]["battle"]["female"].String();
heroClass->imageBattleMale = node["animation"]["battle"]["male"].String();
//MODS COMPATIBILITY FOR 0.96
heroClass->imageMapFemale = node["animation"]["map"]["female"].String();
heroClass->imageMapMale = node["animation"]["map"]["male"].String();
heroClass->name = node["name"].String();
heroClass->affinity = vstd::find_pos(affinityStr, node["affinity"].String());
if (heroClass->affinity >= 2) //FIXME: MODS COMPATIBILITY
heroClass->affinity = 0;
for(const std::string & pSkill : PrimarySkill::names)
{
@ -122,15 +123,11 @@ CHeroClass *CHeroClassHandler::loadFromJson(const JsonNode & node)
heroClass->secSkillProbability.push_back(node["secondarySkills"][secSkill].Float());
}
//FIXME: MODS COMPATIBILITY
if (!node["commander"].isNull())
VLC->modh->identifiers.requestIdentifier ("creature", node["commander"],
[=](si32 commanderID)
{
VLC->modh->identifiers.requestIdentifier ("creature", node["commander"],
[=](si32 commanderID)
{
heroClass->commander = VLC->creh->creatures[commanderID];
});
}
heroClass->commander = VLC->creh->creatures[commanderID];
});
heroClass->defaultTavernChance = node["defaultTavern"].Float();
for(auto & tavern : node["tavern"].Struct())
@ -200,6 +197,14 @@ void CHeroClassHandler::loadObject(std::string scope, std::string name, const Js
heroClasses.push_back(object);
VLC->modh->identifiers.requestIdentifier(scope, "object", "hero", [=](si32 index)
{
JsonNode classConf;
classConf["heroClass"].String() = name;
classConf.setMeta(scope);
VLC->objtypeh->loadSubObject(name, classConf, index, object->id);
});
VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id);
}
@ -211,6 +216,14 @@ void CHeroClassHandler::loadObject(std::string scope, std::string name, const Js
assert(heroClasses[index] == nullptr); // ensure that this id was not loaded before
heroClasses[index] = object;
VLC->modh->identifiers.requestIdentifier(scope, "object", "hero", [=](si32 index)
{
JsonNode classConf = data["mapObject"];
classConf["heroClass"].String() = name;
classConf.setMeta(scope);
VLC->objtypeh->loadSubObject(name, classConf, index, object->id);
});
VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id);
}
@ -231,16 +244,14 @@ void CHeroClassHandler::afterLoadFinalization()
}
}
ObjectTemplate base = VLC->dobjinfo->pickCandidates(Obj::HERO, 0).front();
for (CHeroClass * hc : heroClasses)
{
base.animationFile = hc->imageMapMale;
base.subid = hc->id;
// replace existing (if any) and add new template.
// Necessary for objects added via mods that don't have any templates in H3
VLC->dobjinfo->eraseAll(Obj::HERO, hc->id);
VLC->dobjinfo->registerTemplate(base);
if (!hc->imageMapMale.empty())
{
JsonNode templ;
templ["animation"].String() = hc->imageMapMale;
VLC->objtypeh->getHandlerFor(Obj::HERO, hc->id)->addTemplate(templ);
}
}
}

View File

@ -6,20 +6,6 @@ include_directories(${Boost_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}
set(lib_SRCS
StdInc.cpp
IGameCallback.cpp
CGameInfoCallback.cpp
CGameState.cpp
CObjectHandler.cpp
Connection.cpp
NetPacksLib.cpp
registerTypes/RegisterTypes.cpp
registerTypes/TypesClientPacks1.cpp
registerTypes/TypesClientPacks2.cpp
registerTypes/TypesMapObjects1.cpp
registerTypes/TypesMapObjects2.cpp
registerTypes/TypesPregamePacks.cpp
registerTypes/TypesServerPacks.cpp
filesystem/AdapterLoaders.cpp
filesystem/CCompressedStream.cpp
@ -33,6 +19,22 @@ set(lib_SRCS
filesystem/Filesystem.cpp
filesystem/ResourceID.cpp
mapObjects/CArmedInstance.cpp
mapObjects/CBank.cpp
mapObjects/CGHeroInstance.cpp
mapObjects/CGMarket.cpp
mapObjects/CGPandoraBox.cpp
mapObjects/CGTownInstance.cpp
mapObjects/CObjectClassesHandler.cpp
mapObjects/CObjectHandler.cpp
mapObjects/CommonConstructors.cpp
mapObjects/CQuest.cpp
mapObjects/CRewardableConstructor.cpp
mapObjects/CRewardableObject.cpp
mapObjects/JsonRandom.cpp
mapObjects/MiscObjects.cpp
mapObjects/ObjectTemplate.cpp
logging/CBasicLogConfigurator.cpp
logging/CLogger.cpp
@ -63,7 +65,6 @@ set(lib_SRCS
CConsoleHandler.cpp
CCreatureHandler.cpp
CCreatureSet.cpp
CDefObjInfoHandler.cpp
CGameInterface.cpp
CGeneralTextHandler.cpp
CHeroHandler.cpp
@ -81,6 +82,21 @@ set(lib_SRCS
ResourceSet.cpp
VCMI_Lib.cpp
VCMIDirs.cpp
IGameCallback.cpp
CGameInfoCallback.cpp
CGameState.cpp
Connection.cpp
NetPacksLib.cpp
registerTypes/RegisterTypes.cpp
registerTypes/TypesClientPacks1.cpp
registerTypes/TypesClientPacks2.cpp
registerTypes/TypesMapObjects1.cpp
registerTypes/TypesMapObjects2.cpp
registerTypes/TypesMapObjects3.cpp
registerTypes/TypesPregamePacks.cpp
registerTypes/TypesServerPacks.cpp
)
set(lib_HEADERS
@ -89,6 +105,9 @@ set(lib_HEADERS
filesystem/CInputStream.h
filesystem/ISimpleResourceLoader.h
mapObjects/MapObjects.h
CSoundBase.h
AI_Base.h
CondSh.h
ConstTransitivePtr.h
@ -118,5 +137,5 @@ set_target_properties(vcmi PROPERTIES ${PCH_PROPERTIES})
cotire(vcmi)
if (NOT APPLE) # Already inside vcmiclient bundle
install(TARGETS vcmi DESTINATION ${LIB_DIR})
install(TARGETS vcmi DESTINATION ${LIB_DIR})
endif()

View File

@ -1,6 +1,6 @@
#include "StdInc.h"
#include "CModHandler.h"
#include "CDefObjInfoHandler.h"
#include "mapObjects/CObjectClassesHandler.h"
#include "JsonNode.h"
#include "filesystem/Filesystem.h"
#include "filesystem/AdapterLoaders.h"
@ -10,7 +10,7 @@
#include "CArtHandler.h"
#include "CTownHandler.h"
#include "CHeroHandler.h"
#include "CObjectHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "StringConstants.h"
#include "CStopWatch.h"
#include "IHandlerBase.h"
@ -26,6 +26,11 @@
*
*/
CIdentifierStorage::CIdentifierStorage():
state(LOADING)
{
}
void CIdentifierStorage::checkIdentifier(std::string & ID)
{
if (boost::algorithm::ends_with(ID, "."))
@ -81,7 +86,10 @@ void CIdentifierStorage::requestIdentifier(ObjectCallback callback)
assert(!callback.localScope.empty());
scheduledRequests.push_back(callback);
if (state != FINISHED) // enqueue request if loading is still in progress
scheduledRequests.push_back(callback);
else // execute immediately for "late" requests
resolveIdentifier(callback);
}
void CIdentifierStorage::requestIdentifier(std::string scope, std::string type, std::string name, const std::function<void(si32)> & callback)
@ -120,6 +128,19 @@ void CIdentifierStorage::tryRequestIdentifier(std::string type, const JsonNode &
requestIdentifier(ObjectCallback(name.meta, pair.first, type, pair.second, callback, true));
}
boost::optional<si32> CIdentifierStorage::getIdentifier(std::string scope, std::string type, std::string name, bool silent)
{
auto pair = splitString(name, ':'); // remoteScope:name
auto idList = getPossibleIdentifiers(ObjectCallback(scope, pair.first, type, pair.second, std::function<void(si32)>(), silent));
if (idList.size() == 1)
return idList.front().id;
if (!silent)
logGlobal->errorStream() << "Failed to resolve identifier " << name << " of type " << type << " from mod " << scope;
return boost::optional<si32>();
}
boost::optional<si32> CIdentifierStorage::getIdentifier(std::string type, const JsonNode & name, bool silent)
{
auto pair = splitString(name.String(), ':'); // remoteScope:name
@ -128,7 +149,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string type, const
if (idList.size() == 1)
return idList.front().id;
if (!silent)
logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " from mod " << type;
logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " of type " << type << " from mod " << name.meta;
return boost::optional<si32>();
}
@ -142,7 +163,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, b
if (idList.size() == 1)
return idList.front().id;
if (!silent)
logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " from mod " << name.meta;
logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " of type " << pair2.first << " from mod " << name.meta;
return boost::optional<si32>();
}
@ -210,7 +231,9 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
}
if (request.optional && identifiers.empty()) // failed to resolve optinal ID
{
return true;
}
// error found. Try to generate some debug info
if (identifiers.size() == 0)
@ -229,22 +252,25 @@ bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request)
void CIdentifierStorage::finalize()
{
state = FINALIZING;
bool errorsFound = false;
for(const ObjectCallback & request : scheduledRequests)
//Note: we may receive new requests during resolution phase -> end may change -> range for can't be used
for(auto it = scheduledRequests.begin(); it != scheduledRequests.end(); it++)
{
errorsFound |= !resolveIdentifier(request);
errorsFound |= !resolveIdentifier(*it);
}
if (errorsFound)
{
for(auto object : registeredObjects)
{
logGlobal->traceStream() << object.first << " -> " << object.second.id;
logGlobal->traceStream() << object.second.scope << " : " << object.first << " -> " << object.second.id;
}
logGlobal->errorStream() << "All known identifiers were dumped into log file";
}
assert(errorsFound == false);
state = FINISHED;
}
CContentHandler::ContentTypeHandler::ContentTypeHandler(IHandlerBase * handler, std::string objectName):
@ -347,10 +373,11 @@ CContentHandler::CContentHandler()
handlers.insert(std::make_pair("artifacts", ContentTypeHandler(VLC->arth, "artifact")));
handlers.insert(std::make_pair("creatures", ContentTypeHandler(VLC->creh, "creature")));
handlers.insert(std::make_pair("factions", ContentTypeHandler(VLC->townh, "faction")));
handlers.insert(std::make_pair("objects", ContentTypeHandler(VLC->objtypeh, "object")));
handlers.insert(std::make_pair("heroes", ContentTypeHandler(VLC->heroh, "hero")));
handlers.insert(std::make_pair("spells", ContentTypeHandler(VLC->spellh, "spell")));
handlers.insert(std::make_pair("spells", ContentTypeHandler(VLC->spellh, "spell")));
//TODO: bonuses, something else?
//TODO: any other types of moddables?
}
bool CContentHandler::preloadModData(std::string modName, JsonNode modConfig, bool validate)

View File

@ -25,6 +25,13 @@ class IHandlerBase;
/// if possible, objects ID's should be in format <type>.<name>, camelCase e.g. "creature.grandElf"
class CIdentifierStorage
{
enum ELoadingState
{
LOADING,
FINALIZING,
FINISHED
};
struct ObjectCallback // entry created on ID request
{
std::string localScope; /// scope from which this ID was requested
@ -52,6 +59,8 @@ class CIdentifierStorage
std::multimap<std::string, ObjectData > registeredObjects;
std::vector<ObjectCallback> scheduledRequests;
ELoadingState state;
/// Check if identifier can be valid (camelCase, point as separator)
void checkIdentifier(std::string & ID);
@ -59,6 +68,7 @@ class CIdentifierStorage
bool resolveIdentifier(const ObjectCallback & callback);
std::vector<ObjectData> getPossibleIdentifiers(const ObjectCallback & callback);
public:
CIdentifierStorage();
/// request identifier for specific object name.
/// Function callback will be called during ID resolution phase of loading
void requestIdentifier(std::string scope, std::string type, std::string name, const std::function<void(si32)> & callback);
@ -70,6 +80,7 @@ public:
void tryRequestIdentifier(std::string type, const JsonNode & name, const std::function<void(si32)> & callback);
/// get identifier immediately. If identifier is not know and not silent call will result in error message
boost::optional<si32> getIdentifier(std::string scope, std::string type, std::string name, bool silent = false);
boost::optional<si32> getIdentifier(std::string type, const JsonNode & name, bool silent = false);
boost::optional<si32> getIdentifier(const JsonNode & name, bool silent = false);
@ -81,7 +92,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & registeredObjects;
h & registeredObjects & state;
}
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -110,4 +110,14 @@ namespace RandomGeneratorUtil
assert(!container.empty());
return std::next(container.begin(), rand.nextInt(container.size() - 1));
}
template<typename T>
void randomShuffle(std::vector<T>& container, CRandomGenerator & rand)
{
int n = (container.end() - container.begin());
for (int i = n-1; i>0; --i)
{
std::swap (container.begin()[i],container.begin()[rand.nextInt(i+1)]);
}
}
}

View File

@ -11,8 +11,8 @@
#include "CArtHandler.h"
#include "CSpellHandler.h"
#include "filesystem/Filesystem.h"
#include "CDefObjInfoHandler.h"
#include "CObjectHandler.h"
#include "mapObjects/CObjectClassesHandler.h"
#include "mapObjects/CObjectHandler.h"
/*
* CTownHandler.cpp, part of VCMI engine
@ -272,24 +272,12 @@ void CTownHandler::loadBuildingRequirements(CTown &town, CBuilding & building, c
{
if (source.isNull())
return;
if (source.Vector()[0].getType() == JsonNode::DATA_FLOAT)
{
// MODS COMPATIBILITY
CBuilding::TRequired::OperatorAll required;
for(const JsonNode &building : source.Vector())
required.expressions.push_back(BuildingID(building.Float()));
building.requirements = CBuilding::TRequired(required);
}
else
{
BuildingRequirementsHelper hlp;
hlp.building = &building;
hlp.faction = town.faction;
hlp.json = source;
requirementsToLoad.push_back(hlp);
}
BuildingRequirementsHelper hlp;
hlp.building = &building;
hlp.faction = town.faction;
hlp.json = source;
requirementsToLoad.push_back(hlp);
}
void CTownHandler::loadBuilding(CTown &town, const std::string & stringID, const JsonNode & source)
@ -308,56 +296,49 @@ void CTownHandler::loadBuilding(CTown &town, const std::string & stringID, const
ret->resources = TResources(source["cost"]);
ret->produce = TResources(source["produce"]);
//for compatibility with older town mods
//MODS COMPATIBILITY FOR 0.96
if(!ret->produce.nonZero())
{
if (ret->bid == BuildingID::VILLAGE_HALL) ret->produce[Res::GOLD] = 500;
if (ret->bid == BuildingID::TOWN_HALL) ret->produce[Res::GOLD] = 1000;
if (ret->bid == BuildingID::CITY_HALL) ret->produce[Res::GOLD] = 2000;
if (ret->bid == BuildingID::CAPITOL) ret->produce[Res::GOLD] = 4000;
if (ret->bid == BuildingID::GRAIL) ret->produce[Res::GOLD] = 5000;
//
if (ret->bid == BuildingID::RESOURCE_SILO)
{
if ((ret->town->primaryRes != Res::WOOD) && (ret->town->primaryRes != Res::ORE) && (ret->town->primaryRes != Res::GOLD))
ret->produce[ret->town->primaryRes] = 1;
else
{
if (ret->town->primaryRes == Res::GOLD) ret->produce[ret->town->primaryRes] = 500;
else
switch (ret->bid) {
break; case BuildingID::VILLAGE_HALL: ret->produce[Res::GOLD] = 500;
break; case BuildingID::TOWN_HALL : ret->produce[Res::GOLD] = 1000;
break; case BuildingID::CITY_HALL : ret->produce[Res::GOLD] = 2000;
break; case BuildingID::CAPITOL : ret->produce[Res::GOLD] = 4000;
break; case BuildingID::GRAIL : ret->produce[Res::GOLD] = 5000;
break; case BuildingID::RESOURCE_SILO :
{
ret->produce[Res::WOOD] = 1;
ret->produce[Res::ORE] = 1;
switch (ret->town->primaryRes)
{
case Res::GOLD:
ret->produce[ret->town->primaryRes] = 500;
break;
case Res::WOOD_AND_ORE:
ret->produce[Res::WOOD] = 1;
ret->produce[Res::ORE] = 1;
break;
default:
ret->produce[ret->town->primaryRes] = 1;
break;
}
}
}
}
}
loadBuildingRequirements(town, *ret, source["requires"]);
if (!source["upgrades"].isNull())
{
//MODS COMPATIBILITY
if (source["upgrades"].getType() == JsonNode::DATA_FLOAT)
ret->upgrade = BuildingID(source["upgrades"].Float());
else
// building id and upgrades can't be the same
if(stringID == source["upgrades"].String())
{
// building id and upgrades can't be the same
if(stringID == source["upgrades"].String())
{
throw std::runtime_error(boost::str(boost::format("Building with ID '%s' of town '%s' can't be an upgrade of the same building.") %
stringID % town.faction->name));
}
VLC->modh->identifiers.requestIdentifier("building." + town.faction->identifier, source["upgrades"], [=](si32 identifier)
{
ret->upgrade = BuildingID(identifier);
});
throw std::runtime_error(boost::str(boost::format("Building with ID '%s' of town '%s' can't be an upgrade of the same building.") %
stringID % town.faction->name));
}
VLC->modh->identifiers.requestIdentifier("building." + town.faction->identifier, source["upgrades"], [=](si32 identifier)
{
ret->upgrade = BuildingID(identifier);
});
}
else
ret->upgrade = BuildingID::NONE;
@ -381,7 +362,6 @@ void CTownHandler::loadStructure(CTown &town, const std::string & stringID, cons
{
auto ret = new CStructure;
//Note: MODS COMPATIBILITY CODE
ret->building = nullptr;
ret->buildable = nullptr;
@ -399,17 +379,10 @@ void CTownHandler::loadStructure(CTown &town, const std::string & stringID, cons
}
else
{
if (source["builds"].getType() == JsonNode::DATA_FLOAT)
VLC->modh->identifiers.requestIdentifier("building." + town.faction->identifier, source["builds"], [=, &town](si32 identifier) mutable
{
ret->buildable = town.buildings[BuildingID(source["builds"].Float())];
}
else
{
VLC->modh->identifiers.requestIdentifier("building." + town.faction->identifier, source["builds"], [=, &town](si32 identifier) mutable
{
ret->buildable = town.buildings[BuildingID(identifier)];
});
}
ret->buildable = town.buildings[BuildingID(identifier)];
});
}
ret->identifier = stringID;
@ -457,16 +430,10 @@ void CTownHandler::loadTownHall(CTown &town, const JsonNode & source)
auto & dst = dstBox[k];
auto & src = srcBox[k];
//MODS COMPATIBILITY
if (src.getType() == JsonNode::DATA_FLOAT)
dst = BuildingID(src.Float());
else
VLC->modh->identifiers.requestIdentifier("building." + town.faction->identifier, src, [&](si32 identifier)
{
VLC->modh->identifiers.requestIdentifier("building." + town.faction->identifier, src, [&](si32 identifier)
{
dst = BuildingID(identifier);
});
}
dst = BuildingID(identifier);
});
}
}
}
@ -554,10 +521,6 @@ void CTownHandler::loadClientData(CTown &town, const JsonNode & source)
info.tavernVideo = "TAVERN.BIK";
//end of legacy assignment
info.advMapVillage = source["adventureMap"]["village"].String();
info.advMapCastle = source["adventureMap"]["castle"].String();
info.advMapCapitol = source["adventureMap"]["capitol"].String();
loadTownHall(town, source["hallSlots"]);
loadStructures(town, source["structures"]);
loadSiegeScreen(town, source["siege"]);
@ -677,20 +640,6 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, std::string identi
faction->name = source["name"].String();
faction->identifier = identifier;
//FIXME: MODS COMPATIBILITY
if (!source["commander"].isNull())
{
VLC->modh->identifiers.requestIdentifier ("creature", source["commander"],
[=](si32 commanderID)
{
for (auto ptr : VLC->heroh->classes.heroClasses)
{
if (ptr->commander == nullptr && ptr->faction == faction->index)
ptr->commander = VLC->creh->creatures[commanderID];
}
});
}
faction->creatureBg120 = source["creatureBackground"]["120px"].String();
faction->creatureBg130 = source["creatureBackground"]["130px"].String();
@ -723,6 +672,8 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
auto object = loadFromJson(data, name);
object->index = factions.size();
factions.push_back(object);
if (object->town)
{
auto & info = object->town->clientInfo;
@ -730,9 +681,16 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
info.icons[0][1] = 8 + object->index * 4 + 1;
info.icons[1][0] = 8 + object->index * 4 + 2;
info.icons[1][1] = 8 + object->index * 4 + 3;
}
factions.push_back(object);
VLC->modh->identifiers.requestIdentifier(scope, "object", "town", [=](si32 index)
{
// register town once objects are loaded
JsonNode config = data["town"]["mapObject"];
config["faction"].String() = object->identifier;
config["faction"].meta = scope;
VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
});
}
VLC->modh->identifiers.registerObject(scope, "faction", name, object->index);
}
@ -741,6 +699,9 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
{
auto object = loadFromJson(data, name);
object->index = index;
assert(factions[index] == nullptr); // ensure that this id was not loaded before
factions[index] = object;
if (object->town)
{
auto & info = object->town->clientInfo;
@ -748,10 +709,25 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
info.icons[0][1] = (GameConstants::F_NUMBER + object->index) * 2 + 1;
info.icons[1][0] = object->index * 2 + 0;
info.icons[1][1] = object->index * 2 + 1;
}
assert(factions[index] == nullptr); // ensure that this id was not loaded before
factions[index] = object;
VLC->modh->identifiers.requestIdentifier(scope, "object", "town", [=](si32 index)
{
// register town once objects are loaded
JsonNode config = data["town"]["mapObject"];
config["faction"].String() = object->identifier;
config["faction"].meta = scope;
VLC->objtypeh->loadSubObject(object->identifier, config, index, object->index);
// MODS COMPATIBILITY FOR 0.96
auto & advMap = data["town"]["adventureMap"];
if (!advMap["fort"].isNull())
{
JsonNode config;
config["appearance"] = advMap["fort"];
VLC->objtypeh->getHandlerFor(index, object->index)->addTemplate(config);
}
});
}
VLC->modh->identifiers.registerObject(scope, "faction", name, object->index);
}
@ -759,38 +735,6 @@ void CTownHandler::loadObject(std::string scope, std::string name, const JsonNod
void CTownHandler::afterLoadFinalization()
{
initializeRequirements();
ObjectTemplate base = VLC->dobjinfo->pickCandidates(Obj::TOWN, 0).front();
for (CFaction * fact : factions)
{
if (fact->town)
{
base.animationFile = fact->town->clientInfo.advMapCastle;
base.subid = fact->index;
// replace existing (if any) and add new template.
// Necessary for objects added via mods that don't have any templates in H3
VLC->dobjinfo->eraseAll(Obj::TOWN, fact->index);
VLC->dobjinfo->registerTemplate(base);
assert(fact->town->dwellings.size() == fact->town->dwellingNames.size());
for (size_t i=0; i<fact->town->dwellings.size(); i++)
{
ObjectTemplate base = VLC->dobjinfo->pickCandidates(Obj::CREATURE_GENERATOR1, 0).front();
//both unupgraded and upgraded get same dwelling
for (auto cre : fact->town->creatures[i])
{
base.subid = 80 + cre;
base.animationFile = fact->town->dwellings[i];
if (VLC->objh->cregens.count(cre) == 0)
{
VLC->dobjinfo->registerTemplate(base);
VLC->objh->cregens[80 + cre] = cre; //map of dwelling -> creature id
}
}
}
}
}
}
void CTownHandler::initializeRequirements()
@ -824,4 +768,4 @@ std::set<TFaction> CTownHandler::getAllowedFactions() const
allowedFactions.insert(i);
return allowedFactions;
}
}

View File

@ -190,10 +190,6 @@ public:
/// NOTE: index in vector is meaningless. Vector used instead of list for a bit faster access
std::vector<ConstTransitivePtr<CStructure> > structures;
std::string advMapVillage;
std::string advMapCastle;
std::string advMapCapitol;
std::string siegePrefix;
std::vector<Point> siegePositions;
CreatureID siegeShooter; // shooter creature ID
@ -201,7 +197,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & icons & iconSmall & iconLarge & tavernVideo & musicTheme & townBackground & guildBackground & guildWindow & buildingsIcons & hallBackground;
h & advMapVillage & advMapCastle & advMapCapitol & hallSlots & structures;
h & hallSlots & structures;
h & siegePrefix & siegePositions & siegeShooter;
}
} clientInfo;

View File

@ -14,7 +14,6 @@
#include <typeinfo> //XXX this is in namespace std if you want w/o use typeinfo.h?
#include <type_traits>
#include <boost/variant.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/int.hpp>
@ -24,7 +23,7 @@
#include "ConstTransitivePtr.h"
#include "CCreatureSet.h" //for CStackInstance
#include "CObjectHandler.h" //for CArmedInstance
#include "mapObjects/CGHeroInstance.h"
#include "mapping/CCampaignHandler.h" //for CCampaignState
#include "rmg/CMapGenerator.h" // for CMapGenOptions

View File

@ -13,7 +13,7 @@
#include "StdInc.h"
#include "VCMI_Lib.h"
#include "CDefObjInfoHandler.h"
#include "mapObjects/CObjectClassesHandler.h"
#include "CArtHandler.h"
#include "CCreatureHandler.h"
#include "CSpellHandler.h"

View File

@ -14,9 +14,10 @@
#include "CHeroHandler.h" // for CHeroHandler
#include "CSpellHandler.h" // for CSpell
#include "NetPacks.h"
#include "CBonusTypeHandler.h" // for CBonusTypeHandler
#include "CBonusTypeHandler.h"
#include "Connection.h" // for SAVEGAME_MAGIC
#include "mapObjects/CObjectClassesHandler.h"
void CPrivilagedInfoCallback::getFreeTiles (std::vector<int3> &tiles) const
{

View File

@ -737,7 +737,7 @@ void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source)
void JsonUtils::inherit(JsonNode & descendant, const JsonNode & base)
{
JsonNode inheritedNode(base);
JsonNode inheritedNode(base);
merge(inheritedNode,descendant);
descendant.swap(inheritedNode);
}

View File

@ -108,19 +108,14 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & meta;
// simple saving - save json in its string interpretation
if (h.saving)
{
std::ostringstream stream;
stream << *this;
std::string str = stream.str();
h & str;
}
else
{
std::string str;
h & str;
JsonNode(str.c_str(), str.size()).swap(*this);
h & type;
switch (type) {
break; case DATA_NULL:
break; case DATA_BOOL: h & data.Bool;
break; case DATA_FLOAT: h & data.Float;
break; case DATA_STRING: h & data.String;
break; case DATA_VECTOR: h & data.Vector;
break; case DATA_STRUCT: h & data.Struct;
}
}
};

View File

@ -1,11 +1,10 @@
#pragma once
#include <boost/variant.hpp>
#include "NetPacksBase.h"
#include "BattleAction.h"
#include "HeroBonus.h"
#include "mapObjects/CGHeroInstance.h"
#include "CCreatureSet.h"
#include "mapping/CMapInfo.h"
#include "StartInfo.h"
@ -1022,11 +1021,10 @@ namespace ObjProperty
BONUS_VALUE_FIRST, BONUS_VALUE_SECOND, //used in Rampart for special building that generates resources (storing resource type and quantity)
//creature-bank specific
BANK_DAYCOUNTER, BANK_CLEAR_ARTIFACTS, BANK_ADD_ARTIFACT, BANK_MULTIPLIER, BANK_CONFIG_PRESET,
BANK_CLEAR_CONFIG, BANK_INIT_ARMY, BANK_RESET,
BANK_DAYCOUNTER, BANK_RESET, BANK_CLEAR,
//magic spring
LEFT_VISITED, RIGHT_VISITED, LEFTRIGHT_CLEAR
//object with reward
REWARD_RESET, REWARD_SELECT
};
}
@ -1036,7 +1034,7 @@ struct SetObjectProperty : public CPackForClient//1001
void applyCl(CClient *cl);
ObjectInstanceID id;
ui8 what; //1 - owner; 2 - blockvis; 3 - first stack count; 4 - visitors; 5 - visited; 6 - ID (if 34 then also def is replaced)
ui8 what; // see ObjProperty enum
ui32 val;
SetObjectProperty(){type = 1001;};
SetObjectProperty(ObjectInstanceID ID, ui8 What, ui32 Val):id(ID),what(What),val(Val){type = 1001;};
@ -1053,14 +1051,44 @@ struct SetHoverName : public CPackForClient//1002
ObjectInstanceID id;
MetaString name;
SetHoverName(){type = 1002;};
SetHoverName(ObjectInstanceID ID, MetaString& Name):id(ID),name(Name){type = 1002;};
SetHoverName(){type = 1002;}
SetHoverName(ObjectInstanceID ID, MetaString& Name):id(ID),name(Name){type = 1002;}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & name;
}
};
struct ChangeObjectVisitors : public CPackForClient // 1003
{
enum VisitMode
{
VISITOR_ADD, // mark hero as one that have visited this object
VISITOR_REMOVE, // unmark visitor, reversed to ADD
VISITOR_CLEAR // clear all visitors from this object (object reset)
};
ui32 mode; // uses VisitMode enum
ObjectInstanceID object;
ObjectInstanceID hero; // note: hero owner will be also marked as "visited" this object
DLL_LINKAGE void applyGs(CGameState *gs);
ChangeObjectVisitors()
{ type = 1003; }
ChangeObjectVisitors(ui32 mode, ObjectInstanceID object, ObjectInstanceID heroID = ObjectInstanceID(-1)):
mode(mode),
object(object),
hero(heroID)
{ type = 1003; }
template <typename Handler> void serialize(Handler &h, const int version)
{
h & object & hero & mode;
}
};
struct HeroLevelUp : public Query//2000
{
void applyCl(CClient *cl);
@ -1499,7 +1527,7 @@ struct ObstaclesRemoved : public CPackForClient //3014
}
};
struct CatapultAttack : public CPackForClient //3015
struct DLL_LINKAGE CatapultAttack : public CPackForClient //3015
{
struct AttackInfo
{
@ -1515,8 +1543,7 @@ struct CatapultAttack : public CPackForClient //3015
}
};
DLL_LINKAGE CatapultAttack();
DLL_LINKAGE ~CatapultAttack();
CatapultAttack() {type = 3015;}
DLL_LINKAGE void applyGs(CGameState *gs);
void applyCl(CClient *cl);

View File

@ -25,7 +25,7 @@ struct ArtSlotInfo;
#include "GameConstants.h"
struct CPack
struct DLL_LINKAGE CPack
{
ui16 type;
@ -37,7 +37,7 @@ struct CPack
logNetwork->errorStream() << "CPack serialized... this should not happen!";
}
void applyGs(CGameState *gs) { }
virtual std::string toString() const { return boost::str(boost::format("{CPack: type '%d'}") % type); }
DLL_LINKAGE virtual std::string toString() const { return boost::str(boost::format("{CPack: type '%d'}") % type); }
};
std::ostream & operator<<(std::ostream & out, const CPack * pack);
@ -197,4 +197,4 @@ struct ArtifactLocation
{
h & artHolder & slot;
}
};
};

View File

@ -2,10 +2,10 @@
#include "NetPacks.h"
#include "CGeneralTextHandler.h"
#include "CDefObjInfoHandler.h"
#include "mapObjects/CObjectClassesHandler.h"
#include "CArtHandler.h"
#include "CHeroHandler.h"
#include "CObjectHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "CModHandler.h"
#include "VCMI_Lib.h"
#include "mapping/CMap.h"
@ -124,6 +124,8 @@ DLL_LINKAGE void HeroVisitCastle::applyGs( CGameState *gs )
CGHeroInstance *h = gs->getHero(hid);
CGTownInstance *t = gs->getTown(tid);
assert(h);
assert(t);
if(start())
t->setVisitingHero(h);
else
@ -227,15 +229,14 @@ DLL_LINKAGE void GiveBonus::applyGs( CGameState *gs )
&& gs->map->objects[bonus.sid]->ID == Obj::EVENT) //it's morale/luck bonus from an event without description
{
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
// Some of(?) versions of H3 use %s here instead of %d. Try to replace both of them
boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val)));
boost::replace_first(descr,"%s",boost::lexical_cast<std::string>(std::abs(bonus.val)));
}
else
{
bdescr.toString(descr);
}
// Some of(?) versions of H3 use %s here instead of %d. Try to replace both of them
boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val)));
boost::replace_first(descr,"%s",boost::lexical_cast<std::string>(std::abs(bonus.val)));
}
DLL_LINKAGE void ChangeObjPos::applyGs( CGameState *gs )
@ -251,6 +252,23 @@ DLL_LINKAGE void ChangeObjPos::applyGs( CGameState *gs )
gs->map->addBlockVisTiles(obj);
}
DLL_LINKAGE void ChangeObjectVisitors::applyGs( CGameState *gs )
{
switch (mode) {
case VISITOR_ADD:
gs->getHero(hero)->visitedObjects.insert(object);
gs->getPlayer(gs->getHero(hero)->tempOwner)->visitedObjects.insert(object);
break;
case VISITOR_CLEAR:
for (CGHeroInstance * hero : gs->map->allHeroes)
hero->visitedObjects.erase(object); // remove visit info from all heroes, including those that are not present on map
break;
case VISITOR_REMOVE:
gs->getHero(hero)->visitedObjects.erase(object);
break;
}
}
DLL_LINKAGE void PlayerEndsGame::applyGs( CGameState *gs )
{
PlayerState *p = gs->getPlayer(player);
@ -547,7 +565,7 @@ DLL_LINKAGE void GiveHero::applyGs( CGameState *gs )
//bonus system
h->detachFrom(&gs->globalEffects);
h->attachTo(gs->getPlayer(player));
h->appearance = VLC->dobjinfo->pickCandidates(Obj::HERO, h->type->heroClass->id).front();
h->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, h->type->heroClass->id)->getTemplates().front();
gs->map->removeBlockVisTiles(h,true);
h->setOwner(player);
@ -588,9 +606,9 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs )
o->subID = subID;
o->pos = pos;
const TerrainTile &t = gs->map->getTile(pos);
o->appearance = VLC->dobjinfo->pickCandidates(o->ID, o->subID, t.terType).front();
o->appearance = VLC->objtypeh->getHandlerFor(o->ID, o->subID)->getTemplates(t.terType).front();
id = o->id = ObjectInstanceID(gs->map->objects.size());
o->hoverName = VLC->generaltexth->names[ID];
o->hoverName = VLC->objtypeh->getObjectName(ID);
gs->map->objects.push_back(o);
gs->map->addBlockVisTiles(o);
@ -1477,16 +1495,6 @@ DLL_LINKAGE void ObstaclesRemoved::applyGs( CGameState *gs )
}
}
DLL_LINKAGE CatapultAttack::CatapultAttack()
{
type = 3015;
}
DLL_LINKAGE CatapultAttack::~CatapultAttack()
{
}
DLL_LINKAGE void CatapultAttack::applyGs( CGameState *gs )
{
if(gs->curB && gs->curB->siege != CGTownInstance::NONE) //if there is a battle and it's a siege

View File

@ -14,9 +14,9 @@
#include "CArtHandler.h"
#include "CBonusTypeHandler.h"
#include "CCreatureHandler.h"
#include "CDefObjInfoHandler.h"
#include "mapObjects/CObjectClassesHandler.h"
#include "CHeroHandler.h"
#include "CObjectHandler.h"
#include "mapObjects/CObjectHandler.h"
#include "CTownHandler.h"
#include "CBuildingHandler.h"
#include "CSpellHandler.h"
@ -45,11 +45,11 @@ DLL_LINKAGE void preinitDLL(CConsoleHandler *Console)
DLL_LINKAGE void loadDLLClasses()
{
try
//try
{
VLC->init();
}
HANDLE_EXCEPTION;
//HANDLE_EXCEPTION;
}
const IBonusTypeHandler * LibClasses::getBth() const
@ -109,7 +109,7 @@ void LibClasses::init()
createHandler(objh, "Object", pomtime);
createHandler(dobjinfo, "Def information", pomtime);
createHandler(objtypeh, "Object types information", pomtime);
createHandler(spellh, "Spell", pomtime);
@ -135,7 +135,7 @@ void LibClasses::clear()
delete creh;
delete townh;
delete objh;
delete dobjinfo;
delete objtypeh;
delete spellh;
delete modh;
delete bth;
@ -152,7 +152,7 @@ void LibClasses::makeNull()
creh = nullptr;
townh = nullptr;
objh = nullptr;
dobjinfo = nullptr;
objtypeh = nullptr;
spellh = nullptr;
modh = nullptr;
bth = nullptr;

View File

@ -16,7 +16,7 @@ class CCreatureHandler;
class CSpellHandler;
class CBuildingHandler;
class CObjectHandler;
class CDefObjInfoHandler;
class CObjectClassesHandler;
class CTownHandler;
class CGeneralTextHandler;
class CModHandler;
@ -42,7 +42,7 @@ public:
CCreatureHandler * creh;
CSpellHandler * spellh;
CObjectHandler * objh;
CDefObjInfoHandler * dobjinfo;
CObjectClassesHandler * objtypeh;
CTownHandler * townh;
CGeneralTextHandler * generaltexth;
CModHandler * modh;
@ -60,7 +60,7 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & heroh & arth & creh & townh & objh & dobjinfo & spellh & modh & IS_AI_ENABLED;
h & heroh & arth & creh & townh & objh & objtypeh & spellh & modh & IS_AI_ENABLED;
h & bth;
if(!h.saving)
{

View File

@ -132,8 +132,6 @@
<Unit filename="CCreatureHandler.h" />
<Unit filename="CCreatureSet.cpp" />
<Unit filename="CCreatureSet.h" />
<Unit filename="CDefObjInfoHandler.cpp" />
<Unit filename="CDefObjInfoHandler.h" />
<Unit filename="CGameInfoCallback.cpp" />
<Unit filename="CGameInfoCallback.h" />
<Unit filename="CGameInterface.cpp" />
@ -146,8 +144,6 @@
<Unit filename="CHeroHandler.h" />
<Unit filename="CModHandler.cpp" />
<Unit filename="CModHandler.h" />
<Unit filename="CObjectHandler.cpp" />
<Unit filename="CObjectHandler.h" />
<Unit filename="CObstacleInstance.cpp" />
<Unit filename="CObstacleInstance.h" />
<Unit filename="CRandomGenerator.cpp" />
@ -226,6 +222,37 @@
<Unit filename="logging/CBasicLogConfigurator.h" />
<Unit filename="logging/CLogger.cpp" />
<Unit filename="logging/CLogger.h" />
<Unit filename="mapObjects/CArmedInstance.cpp" />
<Unit filename="mapObjects/CArmedInstance.h" />
<Unit filename="mapObjects/CBank.cpp" />
<Unit filename="mapObjects/CBank.h" />
<Unit filename="mapObjects/CGHeroInstance.cpp" />
<Unit filename="mapObjects/CGHeroInstance.h" />
<Unit filename="mapObjects/CGMarket.cpp" />
<Unit filename="mapObjects/CGMarket.h" />
<Unit filename="mapObjects/CGPandoraBox.cpp" />
<Unit filename="mapObjects/CGPandoraBox.h" />
<Unit filename="mapObjects/CGTownInstance.cpp" />
<Unit filename="mapObjects/CGTownInstance.h" />
<Unit filename="mapObjects/CObjectClassesHandler.cpp" />
<Unit filename="mapObjects/CObjectClassesHandler.h" />
<Unit filename="mapObjects/CObjectHandler.cpp" />
<Unit filename="mapObjects/CObjectHandler.h" />
<Unit filename="mapObjects/CQuest.cpp" />
<Unit filename="mapObjects/CQuest.h" />
<Unit filename="mapObjects/CRewardableConstructor.cpp" />
<Unit filename="mapObjects/CRewardableConstructor.h" />
<Unit filename="mapObjects/CRewardableObject.cpp" />
<Unit filename="mapObjects/CRewardableObject.h" />
<Unit filename="mapObjects/CommonConstructors.cpp" />
<Unit filename="mapObjects/CommonConstructors.h" />
<Unit filename="mapObjects/JsonRandom.cpp" />
<Unit filename="mapObjects/JsonRandom.h" />
<Unit filename="mapObjects/MapObjects.h" />
<Unit filename="mapObjects/MiscObjects.cpp" />
<Unit filename="mapObjects/MiscObjects.h" />
<Unit filename="mapObjects/ObjectTemplate.cpp" />
<Unit filename="mapObjects/ObjectTemplate.h" />
<Unit filename="mapping/CCampaignHandler.cpp" />
<Unit filename="mapping/CCampaignHandler.h" />
<Unit filename="mapping/CMap.cpp" />
@ -246,6 +273,7 @@
<Unit filename="registerTypes/TypesClientPacks2.cpp" />
<Unit filename="registerTypes/TypesMapObjects1.cpp" />
<Unit filename="registerTypes/TypesMapObjects2.cpp" />
<Unit filename="registerTypes/TypesMapObjects3.cpp" />
<Unit filename="registerTypes/TypesPregamePacks.cpp" />
<Unit filename="registerTypes/TypesServerPacks.cpp" />
<Unit filename="rmg/CMapGenOptions.cpp" />

View File

@ -0,0 +1,128 @@
/*
* CArmedInstance.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 "CArmedInstance.h"
#include "../CTownHandler.h"
#include "../CCreatureHandler.h"
#include "../CGeneralTextHandler.h"
#include "../CGameState.h"
using namespace boost::assign;
void CArmedInstance::randomizeArmy(int type)
{
for (auto & elem : stacks)
{
int & randID = elem.second->idRand;
if(randID >= 0)
{
int level = randID / 2;
bool upgrade = randID % 2;
elem.second->setType(VLC->townh->factions[type]->town->creatures[level][upgrade]);
randID = -1;
}
assert(elem.second->valid(false));
assert(elem.second->armyObj == this);
}
return;
}
CArmedInstance::CArmedInstance()
{
battle = nullptr;
}
void CArmedInstance::updateMoraleBonusFromArmy()
{
if(!validTypes(false)) //object not randomized, don't bother
return;
Bonus *b = getBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
if(!b)
{
b = new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
addNewBonus(b);
}
//number of alignments and presence of undead
std::set<TFaction> factions;
bool hasUndead = false;
for(auto slot : Slots())
{
const CStackInstance * inst = slot.second;
const CCreature * creature = VLC->creh->creatures[inst->getCreatureID()];
factions.insert(creature->faction);
// Check for undead flag instead of faction (undead mummies are neutral)
hasUndead |= inst->hasBonusOfType(Bonus::UNDEAD);
}
size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
if (hasBonusOfType(Bonus::NONEVIL_ALIGNMENT_MIX))
{
size_t mixableFactions = 0;
for(TFaction f : factions)
{
if (VLC->townh->factions[f]->alignment != EAlignment::EVIL)
mixableFactions++;
}
if (mixableFactions > 0)
factionsInArmy -= mixableFactions - 1;
}
if(factionsInArmy == 1)
{
b->val = +1;
b->description = VLC->generaltexth->arraytxt[115]; //All troops of one alignment +1
}
else if (!factions.empty()) // no bonus from empty garrison
{
b->val = 2 - factionsInArmy;
b->description = boost::str(boost::format(VLC->generaltexth->arraytxt[114]) % factionsInArmy % b->val); //Troops of %d alignments %d
}
boost::algorithm::trim(b->description);
//-1 modifier for any Undead unit in army
const ui8 UNDEAD_MODIFIER_ID = -2;
Bonus *undeadModifier = getBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
if(hasUndead)
{
if(!undeadModifier)
addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]));
}
else if(undeadModifier)
removeBonus(undeadModifier);
}
void CArmedInstance::armyChanged()
{
updateMoraleBonusFromArmy();
}
CBonusSystemNode * CArmedInstance::whereShouldBeAttached(CGameState *gs)
{
if(tempOwner < PlayerColor::PLAYER_LIMIT)
return gs->getPlayer(tempOwner);
else
return &gs->globalEffects;
}
CBonusSystemNode * CArmedInstance::whatShouldBeAttached()
{
return this;
}

View File

@ -0,0 +1,40 @@
#pragma once
#include "CObjectHandler.h"
#include "../CCreatureSet.h"
/*
* CArmedInstance.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
*
*/
class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet
{
public:
BattleInfo *battle; //set to the current battle, if engaged
void randomizeArmy(int type);
virtual void updateMoraleBonusFromArmy();
void armyChanged() override;
//////////////////////////////////////////////////////////////////////////
// int valOfGlobalBonuses(CSelector selector) const; //used only for castle interface ???
virtual CBonusSystemNode *whereShouldBeAttached(CGameState *gs);
virtual CBonusSystemNode *whatShouldBeAttached();
//////////////////////////////////////////////////////////////////////////
CArmedInstance();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & static_cast<CBonusSystemNode&>(*this);
h & static_cast<CCreatureSet&>(*this);
}
};

329
lib/mapObjects/CBank.cpp Normal file
View File

@ -0,0 +1,329 @@
/*
* CBank.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 "CBank.h"
#include "../NetPacks.h"
#include "../CGeneralTextHandler.h"
#include "../CSoundBase.h"
#include "CommonConstructors.h"
#include "../CSpellHandler.h"
using namespace boost::assign;
///helpers
static std::string & visitedTxt(const bool visited)
{
int id = visited ? 352 : 353;
return VLC->generaltexth->allTexts[id];
}
CBank::CBank()
{
}
CBank::~CBank()
{
}
void CBank::initObj()
{
daycounter = 0;
resetDuration = 0;
VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, cb->gameState()->getRandomGenerator());
}
const std::string & CBank::getHoverText() const
{
bool visited = (bc == nullptr);
hoverName = visitedTxt(visited); // FIXME: USE BANK_SPECIFIC NAMES
return hoverName;
}
void CBank::setConfig(const BankConfig & config)
{
bc.reset(new BankConfig(config));
clear(); // remove all stacks, if any
for (auto & stack : config.guards)
setCreature (SlotID(stacksCount()), stack.type->idNumber, stack.count);
}
void CBank::setPropertyDer (ui8 what, ui32 val)
{
switch (what)
{
case ObjProperty::BANK_DAYCOUNTER: //daycounter
daycounter+=val;
break;
case ObjProperty::BANK_RESET:
initObj();
daycounter = 1; //yes, 1 since "today" daycounter won't be incremented
break;
case ObjProperty::BANK_CLEAR:
bc.reset();
break;
}
}
void CBank::newTurn() const
{
if (bc == nullptr)
{
if (resetDuration != 0)
{
if (daycounter >= resetDuration)
cb->setObjProperty (id, ObjProperty::BANK_RESET, 0); //daycounter 0
else
cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 1); //daycounter++
}
}
}
bool CBank::wasVisited (PlayerColor player) const
{
return !bc; //FIXME: player A should not know about visit done by player B
}
void CBank::onHeroVisit (const CGHeroInstance * h) const
{
if (bc)
{
int banktext = 0;
ui16 soundID = soundBase::ROGUE;
switch (ID)
{
case Obj::CREATURE_BANK:
banktext = 32;
break;
case Obj::DERELICT_SHIP:
banktext = 41;
break;
case Obj::DRAGON_UTOPIA:
banktext = 47;
break;
case Obj::CRYPT:
banktext = 119;
break;
case Obj::SHIPWRECK:
banktext = 122;
break;
case Obj::PYRAMID:
soundID = soundBase::MYSTERY;
banktext = 105;
break;
}
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundID;
bd.text.addTxt(MetaString::ADVOB_TXT, banktext);
//if (ID == Obj::CREATURE_BANK)
// bd.text.addReplacement(VLC->objh->creBanksNames[index]); // FIXME: USE BANK SPECIFIC NAMES
cb->showBlockingDialog (&bd);
}
else
{
InfoWindow iw;
iw.soundID = soundBase::GRAVEYARD;
iw.player = h->getOwner();
if (ID == Obj::PYRAMID) // You come upon the pyramid ... pyramid is completely empty.
{
iw.text << VLC->generaltexth->advobtxt[107];
iw.components.push_back (Component (Component::LUCK, 0 , -2, 0));
GiveBonus gb;
gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::LUCK,Bonus::OBJECT,-2,id.getNum(),VLC->generaltexth->arraytxt[70]);
gb.id = h->id.getNum();
cb->giveHeroBonus(&gb);
}
else
{
iw.text << VLC->generaltexth->advobtxt[33];// This was X, now is completely empty
//iw.text.addReplacement(VLC->objh->creBanksNames[index]); // FIXME: USE BANK SPECIFIC NAMES
}
cb->showInfoDialog(&iw);
}
}
void CBank::doVisit(const CGHeroInstance * hero) const
{
int textID = -1;
InfoWindow iw;
iw.player = hero->getOwner();
MetaString loot;
switch (ID)
{
case Obj::CREATURE_BANK:
case Obj::DRAGON_UTOPIA:
textID = 34;
break;
case Obj::DERELICT_SHIP:
if (!bc)
textID = 43;
else
{
GiveBonus gbonus;
gbonus.id = hero->id.getNum();
gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.sid = ID;
gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[101];
gbonus.bonus.type = Bonus::MORALE;
gbonus.bonus.val = -1;
cb->giveHeroBonus(&gbonus);
textID = 42;
iw.components.push_back (Component (Component::MORALE, 0 , -1, 0));
}
break;
case Obj::CRYPT:
if (bc)
textID = 121;
else
{
iw.components.push_back (Component (Component::MORALE, 0 , -1, 0));
GiveBonus gbonus;
gbonus.id = hero->id.getNum();
gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.sid = ID;
gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[ID];
gbonus.bonus.type = Bonus::MORALE;
gbonus.bonus.val = -1;
cb->giveHeroBonus(&gbonus);
textID = 120;
iw.components.push_back (Component (Component::MORALE, 0 , -1, 0));
}
break;
case Obj::SHIPWRECK:
if (bc)
textID = 124;
else
textID = 123;
break;
case Obj::PYRAMID:
textID = 106;
}
//grant resources
if (bc)
{
for (int it = 0; it < bc->resources.size(); it++)
{
if (bc->resources[it] != 0)
{
iw.components.push_back (Component (Component::RESOURCE, it, bc->resources[it], 0));
loot << "%d %s";
loot.addReplacement(iw.components.back().val);
loot.addReplacement(MetaString::RES_NAMES, iw.components.back().subtype);
cb->giveResource (hero->getOwner(), static_cast<Res::ERes>(it), bc->resources[it]);
}
}
//grant artifacts
for (auto & elem : bc->artifacts)
{
iw.components.push_back (Component (Component::ARTIFACT, elem, 0, 0));
loot << "%s";
loot.addReplacement(MetaString::ART_NAMES, elem);
cb->giveHeroNewArtifact (hero, VLC->arth->artifacts[elem], ArtifactPosition::FIRST_AVAILABLE);
}
//display loot
if (!iw.components.empty())
{
iw.text.addTxt (MetaString::ADVOB_TXT, textID);
if (textID == 34)
{
const CCreature * strongest = boost::range::max_element(bc->guards, [](const CStackBasicDescriptor & a, const CStackBasicDescriptor & b)
{
return a.type->fightValue < b.type->fightValue;
})->type;
iw.text.addReplacement(MetaString::CRE_PL_NAMES, strongest->idNumber);
iw.text.addReplacement(loot.buildList());
}
cb->showInfoDialog(&iw);
}
if (!bc->spells.empty())
{
std::set<SpellID> spells;
bool noWisdom = false;
for (SpellID spell : bc->spells)
{
iw.text.addTxt (MetaString::SPELL_NAME, spell);
if (VLC->spellh->objects[spell]->level <= hero->getSecSkillLevel(SecondarySkill::WISDOM) + 2)
{
spells.insert(spell);
iw.components.push_back(Component (Component::SPELL, spell, 0, 0));
}
else
noWisdom = true;
}
if (!hero->getArt(ArtifactPosition::SPELLBOOK))
iw.text.addTxt (MetaString::ADVOB_TXT, 109); //no spellbook
else if (noWisdom)
iw.text.addTxt (MetaString::ADVOB_TXT, 108); //no expert Wisdom
if (spells.empty())
cb->changeSpells (hero, true, spells);
}
loot.clear();
iw.components.clear();
iw.text.clear();
//grant creatures
CCreatureSet ourArmy;
for (auto slot : bc->creatures)
{
ourArmy.addToSlot(ourArmy.getSlotFor(slot.type->idNumber), slot.type->idNumber, slot.count);
}
for (auto & elem : ourArmy.Slots())
{
iw.components.push_back(Component(*elem.second));
loot << "%s";
loot.addReplacement(*elem.second);
}
if (ourArmy.Slots().size())
{
if (ourArmy.Slots().size() == 1 && ourArmy.Slots().begin()->second->count == 1)
iw.text.addTxt (MetaString::ADVOB_TXT, 185);
else
iw.text.addTxt (MetaString::ADVOB_TXT, 186);
iw.text.addReplacement(loot.buildList());
iw.text.addReplacement(hero->name);
cb->showInfoDialog(&iw);
cb->giveCreatures(this, hero, ourArmy, false);
}
cb->setObjProperty (id, ObjProperty::BANK_CLEAR, 0); //bc = nullptr
}
}
void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
{
if (result.winner == 0)
{
doVisit(hero);
}
}
void CBank::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
if (answer)
{
if (bc) // not looted bank
cb->startBattleI(hero, this, true);
else
doVisit(hero);
}
}

49
lib/mapObjects/CBank.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include "CObjectHandler.h"
#include "CArmedInstance.h"
/*
* CBank.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
*
*/
class BankConfig;
class CBankInstanceConstructor;
class DLL_LINKAGE CBank : public CArmedInstance
{
std::unique_ptr<BankConfig> bc;
ui32 daycounter;
ui32 resetDuration;
void setPropertyDer(ui8 what, ui32 val) override;
void doVisit(const CGHeroInstance * hero) const;
public:
CBank();
~CBank();
void setConfig(const BankConfig & bc);
void initObj() override;
const std::string & getHoverText() const override;
void newTurn() const override;
bool wasVisited (PlayerColor player) const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & daycounter & bc & resetDuration;
}
friend class CBankInstanceConstructor;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
#pragma once
#include "CObjectHandler.h"
#include "CArmedInstance.h"
#include "../CArtHandler.h" // For CArtifactSet
#include "../CRandomGenerator.h"
/*
* CGHeroInstance.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
*
*/
class CHero;
class CGBoat;
class CGHeroPlaceholder : public CGObjectInstance
{
public:
//subID stores id of hero type. If it's 0xff then following field is used
ui8 power;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & power;
}
};
class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet
{
public:
enum ECanDig
{
CAN_DIG, LACK_OF_MOVEMENT, WRONG_TERRAIN, TILE_OCCUPIED
};
//////////////////////////////////////////////////////////////////////////
ui8 moveDir; //format: 123
// 8 4
// 765
mutable ui8 isStanding, tacticFormationEnabled;
//////////////////////////////////////////////////////////////////////////
ConstTransitivePtr<CHero> type;
TExpType exp; //experience points
ui32 level; //current level of hero
std::string name; //may be custom
std::string biography; //if custom
si32 portrait; //may be custom
si32 mana; // remaining spell points
std::vector<std::pair<SecondarySkill,ui8> > secSkills; //first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert); if hero has ability (-1, -1) it meansthat it should have default secondary abilities
ui32 movement; //remaining movement points
ui8 sex;
bool inTownGarrison; // if hero is in town garrison
ConstTransitivePtr<CGTownInstance> visitedTown; //set if hero is visiting town or in the town garrison
ConstTransitivePtr<CCommanderInstance> commander;
const CGBoat *boat; //set to CGBoat when sailing
//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
std::set<SpellID> spells; //known spells (spell IDs)
std::set<ObjectInstanceID> visitedObjects;
struct DLL_LINKAGE Patrol
{
Patrol(){patrolling=false;patrolRadious=-1;};
bool patrolling;
ui32 patrolRadious;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & patrolling & patrolRadious;
}
} patrol;
struct DLL_LINKAGE HeroSpecial : CBonusSystemNode
{
bool growsWithLevel;
HeroSpecial(){growsWithLevel = false;};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CBonusSystemNode&>(*this);
h & growsWithLevel;
}
};
std::vector<HeroSpecial*> specialty;
struct DLL_LINKAGE SecondarySkillsInfo
{
//skills are determined, initialized at map start
//FIXME remove mutable
mutable CRandomGenerator rand;
ui8 magicSchoolCounter;
ui8 wisdomCounter;
void resetMagicSchoolCounter();
void resetWisdomCounter();
template <typename Handler> void serialize(Handler &h, const int version)
{
h & magicSchoolCounter & wisdomCounter & rand;
}
} skillsInfo;
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
int getSightRadious() const; //sight distance (should be used if player-owned structure)
//////////////////////////////////////////////////////////////////////////
int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
//////////////////////////////////////////////////////////////////////////
bool hasSpellbook() const;
EAlignment::EAlignment getAlignment() const;
const std::string &getBiography() const;
bool needsLastStack()const;
ui32 getTileCost(const TerrainTile &dest, const TerrainTile &from) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
ui32 getLowestCreatureSpeed() const;
int3 getPosition(bool h3m = false) const; //h3m=true - returns position of hero object; h3m=false - returns position of hero 'manifestation'
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
bool canWalkOnSea() const;
int getCurrentLuck(int stack=-1, bool town=false) const;
int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored
// ----- primary and secondary skill, experience, level handling -----
/// Returns true if hero has lower level than should upon his experience.
bool gainsLevel() const;
/// Returns the next primary skill on level up. Can only be called if hero can gain a level up.
PrimarySkill::PrimarySkill nextPrimarySkill() const;
/// Returns the next secondary skill randomly on level up. Can only be called if hero can gain a level up.
boost::optional<SecondarySkill> nextSecondarySkill() const;
/// Gets 0, 1 or 2 secondary skills which are proposed on hero level up.
std::vector<SecondarySkill> getLevelUpProposedSecondarySkills() const;
ui8 getSecSkillLevel(SecondarySkill skill) const; //0 - no skill
/// Returns true if hero has free secondary skill slot.
bool canLearnSkill() const;
void setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si64 value, ui8 abs);
void setSecSkillLevel(SecondarySkill which, int val, bool abs);// abs == 0 - changes by value; 1 - sets to value
void levelUp(std::vector<SecondarySkill> skills);
int maxMovePoints(bool onLand) const;
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
//int getSpellSecLevel(int spell) const; //returns level of secondary ability (fire, water, earth, air magic) known to this hero and applicable to given spell; -1 if error
static int3 convertPosition(int3 src, bool toh3m); //toh3m=true: manifest->h3m; toh3m=false: h3m->manifest
double getFightingStrength() const; // takes attack / defense skill into account
double getMagicStrength() const; // takes knowledge / spell power skill into account
double getHeroStrength() const; // includes fighting and magic strength
ui64 getTotalStrength() const; // includes fighting strength and army strength
TExpType calculateXp(TExpType exp) const; //apply learning skill
ui8 getSpellSchoolLevel(const CSpell * spell, int *outSelectedSchool = nullptr) const; //returns level on which given spell would be cast by this hero (0 - none, 1 - basic etc); optionally returns number of selected school by arg - 0 - air magic, 1 - fire magic, 2 - water magic, 3 - earth magic,
bool canCastThisSpell(const CSpell * spell) const; //determines if this hero can cast given spell; takes into account existing spell in spellbook, existing spellbook and artifact bonuses
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
ECanDig diggingStatus() const; //0 - can dig; 1 - lack of movement; 2 -
//////////////////////////////////////////////////////////////////////////
void setType(si32 ID, si32 subID);
void initHero();
void initHero(HeroTypeID SUBID);
void putArtifact(ArtifactPosition pos, CArtifactInstance *art);
void putInBackpack(CArtifactInstance *art);
void initExp();
void initArmy(IArmyDescriptor *dst = nullptr);
//void giveArtifact (ui32 aid);
void pushPrimSkill(PrimarySkill::PrimarySkill which, int val);
ui8 maxlevelsToMagicSchool() const;
ui8 maxlevelsToWisdom() const;
void Updatespecialty();
void recreateSecondarySkillsBonuses();
void updateSkill(SecondarySkill which, int val);
CGHeroInstance();
virtual ~CGHeroInstance();
//////////////////////////////////////////////////////////////////////////
//
ArtBearer::ArtBearer bearerType() const override;
//////////////////////////////////////////////////////////////////////////
CBonusSystemNode *whereShouldBeAttached(CGameState *gs) override;
std::string nodeName() const override;
void deserializationFix();
void initObj() override;
void onHeroVisit(const CGHeroInstance * h) const override;
const std::string & getHoverText() const override;
protected:
void setPropertyDer(ui8 what, ui32 val) override;//synchr
private:
void levelUpAutomatically();
public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & static_cast<CArtifactSet&>(*this);
h & exp & level & name & biography & portrait & mana & secSkills & movement
& sex & inTownGarrison & spells & patrol & moveDir & skillsInfo;
h & visitedTown & boat;
h & type & specialty & commander;
BONUS_TREE_DESERIALIZATION_FIX
//visitied town pointer will be restored by map serialization method
}
};

335
lib/mapObjects/CGMarket.cpp Normal file
View File

@ -0,0 +1,335 @@
/*
*
* CGMarket.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 "CGMarket.h"
#include "../NetPacks.h"
#include "../CGeneralTextHandler.h"
using namespace boost::assign;
///helpers
static void openWindow(const OpenWindow::EWindow type, const int id1, const int id2 = -1)
{
OpenWindow ow;
ow.window = type;
ow.id1 = id1;
ow.id2 = id2;
IObjectInterface::cb->sendAndApply(&ow);
}
bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode::EMarketMode mode) const
{
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
{
double effectiveness = std::min((getMarketEfficiency() + 1.0) / 20.0, 0.5);
double r = VLC->objh->resVals[id1], //value of given resource
g = VLC->objh->resVals[id2] / effectiveness; //value of wanted resource
if(r>g) //if given resource is more expensive than wanted
{
val2 = ceil(r / g);
val1 = 1;
}
else //if wanted resource is more expensive
{
val1 = (g / r) + 0.5;
val2 = 1;
}
}
break;
case EMarketMode::CREATURE_RESOURCE:
{
const double effectivenessArray[] = {0.0, 0.3, 0.45, 0.50, 0.65, 0.7, 0.85, 0.9, 1.0};
double effectiveness = effectivenessArray[std::min(getMarketEfficiency(), 8)];
double r = VLC->creh->creatures[id1]->cost[6], //value of given creature in gold
g = VLC->objh->resVals[id2] / effectiveness; //value of wanted resource
if(r>g) //if given resource is more expensive than wanted
{
val2 = ceil(r / g);
val1 = 1;
}
else //if wanted resource is more expensive
{
val1 = (g / r) + 0.5;
val2 = 1;
}
}
break;
case EMarketMode::RESOURCE_PLAYER:
val1 = 1;
val2 = 1;
break;
case EMarketMode::RESOURCE_ARTIFACT:
{
double effectiveness = std::min((getMarketEfficiency() + 3.0) / 20.0, 0.6);
double r = VLC->objh->resVals[id1], //value of offered resource
g = VLC->arth->artifacts[id2]->price / effectiveness; //value of bought artifact in gold
if(id1 != 6) //non-gold prices are doubled
r /= 2;
val1 = std::max(1, (int)((g / r) + 0.5)); //don't sell arts for less than 1 resource
val2 = 1;
}
break;
case EMarketMode::ARTIFACT_RESOURCE:
{
double effectiveness = std::min((getMarketEfficiency() + 3.0) / 20.0, 0.6);
double r = VLC->arth->artifacts[id1]->price * effectiveness,
g = VLC->objh->resVals[id2];
// if(id2 != 6) //non-gold prices are doubled
// r /= 2;
val1 = 1;
val2 = std::max(1, (int)((r / g) + 0.5)); //at least one resource is given in return
}
break;
case EMarketMode::CREATURE_EXP:
{
val1 = 1;
val2 = (VLC->creh->creatures[id1]->AIValue / 40) * 5;
}
break;
case EMarketMode::ARTIFACT_EXP:
{
val1 = 1;
int givenClass = VLC->arth->artifacts[id1]->getArtClassSerial();
if(givenClass < 0 || givenClass > 3)
{
val2 = 0;
return false;
}
static const int expPerClass[] = {1000, 1500, 3000, 6000};
val2 = expPerClass[givenClass];
}
break;
default:
assert(0);
return false;
}
return true;
}
bool IMarket::allowsTrade(EMarketMode::EMarketMode mode) const
{
return false;
}
int IMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const
{
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::ARTIFACT_RESOURCE:
case EMarketMode::CREATURE_RESOURCE:
return -1;
default:
return 1;
}
}
std::vector<int> IMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
{
std::vector<int> ret;
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::ARTIFACT_RESOURCE:
case EMarketMode::CREATURE_RESOURCE:
for (int i = 0; i < 7; i++)
ret.push_back(i);
}
return ret;
}
const IMarket * IMarket::castFrom(const CGObjectInstance *obj, bool verbose /*= true*/)
{
switch(obj->ID)
{
case Obj::TOWN:
return static_cast<const CGTownInstance*>(obj);
case Obj::ALTAR_OF_SACRIFICE:
case Obj::BLACK_MARKET:
case Obj::TRADING_POST:
case Obj::TRADING_POST_SNOW:
case Obj::FREELANCERS_GUILD:
return static_cast<const CGMarket*>(obj);
case Obj::UNIVERSITY:
return static_cast<const CGUniversity*>(obj);
default:
if(verbose)
logGlobal->errorStream() << "Cannot cast to IMarket object with ID " << obj->ID;
return nullptr;
}
}
IMarket::IMarket(const CGObjectInstance *O)
:o(O)
{
}
std::vector<EMarketMode::EMarketMode> IMarket::availableModes() const
{
std::vector<EMarketMode::EMarketMode> ret;
for (int i = 0; i < EMarketMode::MARTKET_AFTER_LAST_PLACEHOLDER; i++)
if(allowsTrade((EMarketMode::EMarketMode)i))
ret.push_back((EMarketMode::EMarketMode)i);
return ret;
}
void CGMarket::onHeroVisit(const CGHeroInstance * h) const
{
openWindow(OpenWindow::MARKET_WINDOW,id.getNum(),h->id.getNum());
}
int CGMarket::getMarketEfficiency() const
{
return 5;
}
bool CGMarket::allowsTrade(EMarketMode::EMarketMode mode) const
{
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::RESOURCE_PLAYER:
switch(ID)
{
case Obj::TRADING_POST:
case Obj::TRADING_POST_SNOW:
return true;
default:
return false;
}
case EMarketMode::CREATURE_RESOURCE:
return ID == Obj::FREELANCERS_GUILD;
//case ARTIFACT_RESOURCE:
case EMarketMode::RESOURCE_ARTIFACT:
return ID == Obj::BLACK_MARKET;
case EMarketMode::ARTIFACT_EXP:
case EMarketMode::CREATURE_EXP:
return ID == Obj::ALTAR_OF_SACRIFICE; //TODO? check here for alignment of visiting hero? - would not be coherent with other checks here
case EMarketMode::RESOURCE_SKILL:
return ID == Obj::UNIVERSITY;
default:
return false;
}
}
int CGMarket::availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const
{
return -1;
}
std::vector<int> CGMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
{
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
case EMarketMode::RESOURCE_PLAYER:
return IMarket::availableItemsIds(mode);
default:
return std::vector<int>();
}
}
CGMarket::CGMarket()
:IMarket(this)
{
}
std::vector<int> CGBlackMarket::availableItemsIds(EMarketMode::EMarketMode mode) const
{
switch(mode)
{
case EMarketMode::ARTIFACT_RESOURCE:
return IMarket::availableItemsIds(mode);
case EMarketMode::RESOURCE_ARTIFACT:
{
std::vector<int> ret;
for(const CArtifact *a : artifacts)
if(a)
ret.push_back(a->id);
else
ret.push_back(-1);
return ret;
}
default:
return std::vector<int>();
}
}
void CGBlackMarket::newTurn() const
{
if(cb->getDate(Date::DAY_OF_MONTH) != 1) //new month
return;
SetAvailableArtifacts saa;
saa.id = id.getNum();
cb->pickAllowedArtsSet(saa.arts);
cb->sendAndApply(&saa);
}
void CGUniversity::initObj()
{
std::vector<int> toChoose;
for(int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
{
if(cb->isAllowed(2, i))
{
toChoose.push_back(i);
}
}
if(toChoose.size() < 4)
{
logGlobal->warnStream()<<"Warning: less then 4 available skills was found by University initializer!";
return;
}
// get 4 skills
for(int i = 0; i < 4; ++i)
{
// move randomly one skill to selected and remove from list
auto it = RandomGeneratorUtil::nextItem(toChoose, cb->gameState()->getRandomGenerator());
skills.push_back(*it);
toChoose.erase(it);
}
}
std::vector<int> CGUniversity::availableItemsIds(EMarketMode::EMarketMode mode) const
{
switch (mode)
{
case EMarketMode::RESOURCE_SKILL:
return skills;
default:
return std::vector <int> ();
}
}
void CGUniversity::onHeroVisit(const CGHeroInstance * h) const
{
openWindow(OpenWindow::UNIVERSITY_WINDOW,id.getNum(),h->id.getNum());
}

88
lib/mapObjects/CGMarket.h Normal file
View File

@ -0,0 +1,88 @@
#pragma once
#include "CObjectHandler.h"
/*
* CGMarket.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
*
*/
class DLL_LINKAGE IMarket
{
public:
const CGObjectInstance *o;
IMarket(const CGObjectInstance *O);
virtual ~IMarket() {}
virtual int getMarketEfficiency() const =0;
virtual bool allowsTrade(EMarketMode::EMarketMode mode) const;
virtual int availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const; //-1 if unlimited
virtual std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const;
bool getOffer(int id1, int id2, int &val1, int &val2, EMarketMode::EMarketMode mode) const; //val1 - how many units of id1 player has to give to receive val2 units
std::vector<EMarketMode::EMarketMode> availableModes() const;
static const IMarket *castFrom(const CGObjectInstance *obj, bool verbose = true);
template <typename Handler> void serialize(Handler &h, const int version)
{
h & o;
}
};
class DLL_LINKAGE CGMarket : public CGObjectInstance, public IMarket
{
public:
CGMarket();
///IObjectIntercae
void onHeroVisit(const CGHeroInstance * h) const override; //open trading window
///IMarket
int getMarketEfficiency() const override;
bool allowsTrade(EMarketMode::EMarketMode mode) const override;
int availableUnits(EMarketMode::EMarketMode mode, int marketItemSerial) const override; //-1 if unlimited
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & static_cast<IMarket&>(*this);
}
};
class DLL_LINKAGE CGBlackMarket : public CGMarket
{
public:
std::vector<const CArtifact *> artifacts; //available artifacts
void newTurn() const override; //reset artifacts for black market every month
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGMarket&>(*this);
h & artifacts;
}
};
class DLL_LINKAGE CGUniversity : public CGMarket
{
public:
std::vector<int> skills; //available skills
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const;
void initObj() override;//set skills for trade
void onHeroVisit(const CGHeroInstance * h) const override; //open window
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGMarket&>(*this);
h & skills;
}
};

View File

@ -0,0 +1,364 @@
/*
* CGPandoraBox.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 "CGPandoraBox.h"
#include "../NetPacks.h"
#include "../CSoundBase.h"
#include "../CSpellHandler.h"
using namespace boost::assign;
///helpers
static void showInfoDialog(const PlayerColor playerID, const ui32 txtID, const ui16 soundID)
{
InfoWindow iw;
iw.soundID = soundID;
iw.player = playerID;
iw.text.addTxt(MetaString::ADVOB_TXT,txtID);
IObjectInterface::cb->sendAndApply(&iw);
}
static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16 soundID)
{
const PlayerColor playerID = h->getOwner();
showInfoDialog(playerID,txtID,soundID);
}
void CGPandoraBox::initObj()
{
blockVisit = (ID==Obj::PANDORAS_BOX); //block only if it's really pandora's box (events also derive from that class)
hasGuardians = stacks.size();
}
void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const
{
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundBase::QUEST;
bd.text.addTxt (MetaString::ADVOB_TXT, 14);
cb->showBlockingDialog (&bd);
}
void CGPandoraBox::giveContentsUpToExp(const CGHeroInstance *h) const
{
cb->removeAfterVisit(this);
InfoWindow iw;
iw.player = h->getOwner();
bool changesPrimSkill = false;
for (auto & elem : primskills)
{
if(elem)
{
changesPrimSkill = true;
break;
}
}
if(gainedExp || changesPrimSkill || abilities.size())
{
TExpType expVal = h->calculateXp(gainedExp);
//getText(iw,afterBattle,175,h); //wtf?
iw.text.addTxt(MetaString::ADVOB_TXT, 175); //%s learns something
iw.text.addReplacement(h->name);
if(expVal)
iw.components.push_back(Component(Component::EXPERIENCE,0,expVal,0));
for(int i=0; i<primskills.size(); i++)
if(primskills[i])
iw.components.push_back(Component(Component::PRIM_SKILL,i,primskills[i],0));
for(int i=0; i<abilities.size(); i++)
iw.components.push_back(Component(Component::SEC_SKILL,abilities[i],abilityLevels[i],0));
cb->showInfoDialog(&iw);
//give sec skills
for(int i=0; i<abilities.size(); i++)
{
int curLev = h->getSecSkillLevel(abilities[i]);
if( (curLev && curLev < abilityLevels[i]) || (h->canLearnSkill() ))
{
cb->changeSecSkill(h,abilities[i],abilityLevels[i],true);
}
}
//give prim skills
for(int i=0; i<primskills.size(); i++)
if(primskills[i])
cb->changePrimSkill(h,static_cast<PrimarySkill::PrimarySkill>(i),primskills[i],false);
assert(!cb->isVisitCoveredByAnotherQuery(this, h));
//give exp
if(expVal)
cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false);
}
if(!cb->isVisitCoveredByAnotherQuery(this, h))
giveContentsAfterExp(h);
//Otherwise continuation occurs via post-level-up callback.
}
void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const
{
bool hadGuardians = hasGuardians; //copy, because flag will be emptied after issuing first post-battle message
std::string msg = message; //in case box is removed in the meantime
InfoWindow iw;
iw.player = h->getOwner();
if(spells.size())
{
std::set<SpellID> spellsToGive;
iw.components.clear();
if (spells.size() > 1)
{
iw.text.addTxt(MetaString::ADVOB_TXT, 188); //%s learns spells
}
else
{
iw.text.addTxt(MetaString::ADVOB_TXT, 184); //%s learns a spell
}
iw.text.addReplacement(h->name);
std::vector<ConstTransitivePtr<CSpell> > * sp = &VLC->spellh->objects;
for(auto i=spells.cbegin(); i != spells.cend(); i++)
{
if ((*sp)[*i]->level <= h->getSecSkillLevel(SecondarySkill::WISDOM) + 2) //enough wisdom
{
iw.components.push_back(Component(Component::SPELL,*i,0,0));
spellsToGive.insert(*i);
}
}
if(!spellsToGive.empty())
{
cb->changeSpells(h,true,spellsToGive);
cb->showInfoDialog(&iw);
}
}
if(manaDiff)
{
getText(iw,hadGuardians,manaDiff,176,177,h);
iw.components.push_back(Component(Component::PRIM_SKILL,5,manaDiff,0));
cb->showInfoDialog(&iw);
cb->setManaPoints(h->id, h->mana + manaDiff);
}
if(moraleDiff)
{
getText(iw,hadGuardians,moraleDiff,178,179,h);
iw.components.push_back(Component(Component::MORALE,0,moraleDiff,0));
cb->showInfoDialog(&iw);
GiveBonus gb;
gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::MORALE,Bonus::OBJECT,moraleDiff,id.getNum(),"");
gb.id = h->id.getNum();
cb->giveHeroBonus(&gb);
}
if(luckDiff)
{
getText(iw,hadGuardians,luckDiff,180,181,h);
iw.components.push_back(Component(Component::LUCK,0,luckDiff,0));
cb->showInfoDialog(&iw);
GiveBonus gb;
gb.bonus = Bonus(Bonus::ONE_BATTLE,Bonus::LUCK,Bonus::OBJECT,luckDiff,id.getNum(),"");
gb.id = h->id.getNum();
cb->giveHeroBonus(&gb);
}
iw.components.clear();
iw.text.clear();
for(int i=0; i<resources.size(); i++)
{
if(resources[i] < 0)
iw.components.push_back(Component(Component::RESOURCE,i,resources[i],0));
}
if(iw.components.size())
{
getText(iw,hadGuardians,182,h);
cb->showInfoDialog(&iw);
}
iw.components.clear();
iw.text.clear();
for(int i=0; i<resources.size(); i++)
{
if(resources[i] > 0)
iw.components.push_back(Component(Component::RESOURCE,i,resources[i],0));
}
if(iw.components.size())
{
getText(iw,hadGuardians,183,h);
cb->showInfoDialog(&iw);
}
iw.components.clear();
// getText(iw,afterBattle,183,h);
iw.text.addTxt(MetaString::ADVOB_TXT, 183); //% has found treasure
iw.text.addReplacement(h->name);
for(auto & elem : artifacts)
{
iw.components.push_back(Component(Component::ARTIFACT,elem,0,0));
if(iw.components.size() >= 14)
{
cb->showInfoDialog(&iw);
iw.components.clear();
iw.text.addTxt(MetaString::ADVOB_TXT, 183); //% has found treasure - once more?
iw.text.addReplacement(h->name);
}
}
if(iw.components.size())
{
cb->showInfoDialog(&iw);
}
for(int i=0; i<resources.size(); i++)
if(resources[i])
cb->giveResource(h->getOwner(),static_cast<Res::ERes>(i),resources[i]);
for(auto & elem : artifacts)
cb->giveHeroNewArtifact(h, VLC->arth->artifacts[elem],ArtifactPosition::FIRST_AVAILABLE);
iw.components.clear();
iw.text.clear();
if (creatures.Slots().size())
{ //this part is taken straight from creature bank
MetaString loot;
for(auto & elem : creatures.Slots())
{ //build list of joined creatures
iw.components.push_back(Component(*elem.second));
loot << "%s";
loot.addReplacement(*elem.second);
}
if (creatures.Slots().size() == 1 && creatures.Slots().begin()->second->count == 1)
iw.text.addTxt(MetaString::ADVOB_TXT, 185);
else
iw.text.addTxt(MetaString::ADVOB_TXT, 186);
iw.text.addReplacement(loot.buildList());
iw.text.addReplacement(h->name);
cb->showInfoDialog(&iw);
cb->giveCreatures(this, h, creatures, true);
}
if(!hasGuardians && msg.size())
{
iw.text << msg;
cb->showInfoDialog(&iw);
}
}
void CGPandoraBox::getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const
{
if(afterBattle || !message.size())
{
iw.text.addTxt(MetaString::ADVOB_TXT,text);//%s has lost treasure.
iw.text.addReplacement(h->name);
}
else
{
iw.text << message;
afterBattle = true;
}
}
void CGPandoraBox::getText( InfoWindow &iw, bool &afterBattle, int val, int negative, int positive, const CGHeroInstance * h ) const
{
iw.components.clear();
iw.text.clear();
if(afterBattle || !message.size())
{
iw.text.addTxt(MetaString::ADVOB_TXT,val < 0 ? negative : positive); //%s's luck takes a turn for the worse / %s's luck increases
iw.text.addReplacement(h->name);
}
else
{
iw.text << message;
afterBattle = true;
}
}
void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
{
if(result.winner)
return;
giveContentsUpToExp(hero);
}
void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
if (answer)
{
if (stacksCount() > 0) //if pandora's box is protected by army
{
showInfoDialog(hero,16,0);
cb->startBattleI(hero, this); //grants things after battle
}
else if (message.size() == 0 && resources.size() == 0
&& primskills.size() == 0 && abilities.size() == 0
&& abilityLevels.size() == 0 && artifacts.size() == 0
&& spells.size() == 0 && creatures.Slots().size() > 0
&& gainedExp == 0 && manaDiff == 0 && moraleDiff == 0 && luckDiff == 0) //if it gives nothing without battle
{
showInfoDialog(hero,15,0);
cb->removeObject(this);
}
else //if it gives something without battle
{
giveContentsUpToExp(hero);
}
}
}
void CGPandoraBox::heroLevelUpDone(const CGHeroInstance *hero) const
{
giveContentsAfterExp(hero);
}
void CGEvent::onHeroVisit( const CGHeroInstance * h ) const
{
if(!(availableFor & (1 << h->tempOwner.getNum())))
return;
if(cb->getPlayerSettings(h->tempOwner)->playerID)
{
if(humanActivate)
activated(h);
}
else if(computerActivate)
activated(h);
}
void CGEvent::activated( const CGHeroInstance * h ) const
{
if(stacksCount() > 0)
{
InfoWindow iw;
iw.player = h->tempOwner;
if(message.size())
iw.text << message;
else
iw.text.addTxt(MetaString::ADVOB_TXT, 16);
cb->showInfoDialog(&iw);
cb->startBattleI(h, this);
}
else
{
giveContentsUpToExp(h);
}
}

Some files were not shown because too many files have changed in this diff Show More