1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-28 08:48:48 +02:00

Merge pull request #19 from vcmi/feature/mapObjects

Feature/map objects
This commit is contained in:
DjWarmonger 2014-06-22 14:49:42 +02:00
commit 3ac306f501
138 changed files with 17468 additions and 14820 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;
}

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"
@ -162,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

@ -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"

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;
@ -148,13 +146,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"
@ -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,975 @@
{
"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": [ 0, 0, 1, 3 ]
"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": [ 0, 0, 0, 4 ]
"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

@ -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

@ -287,7 +287,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,6 +104,7 @@ 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();
@ -200,6 +203,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 +222,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 +250,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,20 @@ 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/TypesPregamePacks.cpp
registerTypes/TypesServerPacks.cpp
)
set(lib_HEADERS
@ -89,6 +104,9 @@ set(lib_HEADERS
filesystem/CInputStream.h
filesystem/ISimpleResourceLoader.h
mapObjects/MapObjects.h
CSoundBase.h
AI_Base.h
CondSh.h
ConstTransitivePtr.h
@ -118,5 +136,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

@ -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
@ -554,10 +554,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"]);
@ -723,6 +719,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 +728,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 +746,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 +756,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 +782,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 +815,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);

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"
@ -229,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 )
@ -253,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);
@ -549,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);
@ -590,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);

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

@ -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);
}
}

View File

@ -0,0 +1,72 @@
#pragma once
#include "CObjectHandler.h"
#include "CArmedInstance.h"
/*
* CGPandoraBox.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 CGPandoraBox : public CArmedInstance
{
public:
std::string message;
bool hasGuardians; //helper - after battle even though we have no stacks, allows us to know that there was battle
//gained things:
ui32 gainedExp;
si32 manaDiff; //amount of gained / lost mana
si32 moraleDiff; //morale modifier
si32 luckDiff; //luck modifier
TResources resources;//gained / lost resources
std::vector<si32> primskills;//gained / lost prim skills
std::vector<SecondarySkill> abilities; //gained abilities
std::vector<si32> abilityLevels; //levels of gained abilities
std::vector<ArtifactID> artifacts; //gained artifacts
std::vector<SpellID> spells; //gained spells
CCreatureSet creatures; //gained creatures
void initObj() 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;
void heroLevelUpDone(const CGHeroInstance *hero) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & message & hasGuardians & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills
& abilities & abilityLevels & artifacts & spells & creatures;
}
protected:
void giveContentsUpToExp(const CGHeroInstance *h) const;
void giveContentsAfterExp(const CGHeroInstance *h) const;
private:
void getText( InfoWindow &iw, bool &afterBattle, int val, int negative, int positive, const CGHeroInstance * h ) const;
void getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const;
};
class DLL_LINKAGE CGEvent : public CGPandoraBox //event objects
{
public:
bool removeAfterVisit; //true if event is removed after occurring
ui8 availableFor; //players whom this event is available for
bool computerActivate; //true if computer player can activate this event
bool humanActivate; //true if human player can activate this event
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGPandoraBox &>(*this);
h & removeAfterVisit & availableFor & computerActivate & humanActivate;
}
void onHeroVisit(const CGHeroInstance * h) const override;
private:
void activated(const CGHeroInstance * h) const;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,248 @@
#pragma once
#include "CObjectHandler.h"
#include "CGMarket.h" // For IMarket interface
#include "CArmedInstance.h"
#include "../CTownHandler.h" // For CTown
/*
* CGTownInstance.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 CCastleEvent;
class DLL_LINKAGE CSpecObjInfo
{
public:
virtual ~CSpecObjInfo(){};
PlayerColor player; //owner
};
class DLL_LINKAGE CCreGenAsCastleInfo : public virtual CSpecObjInfo
{
public:
bool asCastle;
ui32 identifier;
ui8 castles[2]; //allowed castles
};
class DLL_LINKAGE CCreGenLeveledInfo : public virtual CSpecObjInfo
{
public:
ui8 minLevel, maxLevel; //minimal and maximal level of creature in dwelling: <0, 6>
};
class DLL_LINKAGE CCreGenLeveledCastleInfo : public CCreGenAsCastleInfo, public CCreGenLeveledInfo
{
};
class DLL_LINKAGE CGDwelling : public CArmedInstance
{
public:
typedef std::vector<std::pair<ui32, std::vector<CreatureID> > > TCreaturesSet;
CSpecObjInfo * info; //h3m info about dewlling
TCreaturesSet creatures; //creatures[level] -> <vector of alternative ids (base creature and upgrades, creatures amount>
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this) & creatures;
}
void initObj() override;
void onHeroVisit(const CGHeroInstance * h) const override;
void newTurn() const override;
void setProperty(ui8 what, ui32 val) override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
private:
void heroAcceptsCreatures(const CGHeroInstance *h) const;
};
class DLL_LINKAGE CGTownBuilding : public IObjectInterface
{
///basic class for town structures handled as map objects
public:
BuildingID ID; //from buildig list
si32 id; //identifies its index on towns vector
CGTownInstance *town;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & ID & id;
}
};
class DLL_LINKAGE COPWBonus : public CGTownBuilding
{///used for OPW bonusing structures
public:
std::set<si32> visitors;
void setProperty(ui8 what, ui32 val) override;
void onHeroVisit (const CGHeroInstance * h) const override;
COPWBonus (BuildingID index, CGTownInstance *TOWN);
COPWBonus (){ID = BuildingID::NONE; town = nullptr;};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGTownBuilding&>(*this);
h & visitors;
}
};
class DLL_LINKAGE CTownBonus : public CGTownBuilding
{
///used for one-time bonusing structures
///feel free to merge inheritance tree
public:
std::set<ObjectInstanceID> visitors;
void setProperty(ui8 what, ui32 val) override;
void onHeroVisit (const CGHeroInstance * h) const override;
CTownBonus (BuildingID index, CGTownInstance *TOWN);
CTownBonus (){ID = BuildingID::NONE; town = nullptr;};
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGTownBuilding&>(*this);
h & visitors;
}
};
class DLL_LINKAGE CTownAndVisitingHero : public CBonusSystemNode
{
public:
CTownAndVisitingHero();
};
struct DLL_LINKAGE GrowthInfo
{
struct Entry
{
int count;
std::string description;
Entry(const std::string &format, int _count);
Entry(int subID, BuildingID building, int _count);
};
std::vector<Entry> entries;
int totalGrowth() const;
};
class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public IMarket
{
public:
enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
CTownAndVisitingHero townAndVis;
const CTown * town;
std::string name; // name of town
si32 builded; //how many buildings has been built this turn
si32 destroyed; //how many buildings has been destroyed this turn
ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
ui32 identifier; //special identifier from h3m (only > RoE maps)
si32 alignment;
std::set<BuildingID> forbiddenBuildings, builtBuildings;
std::vector<CGTownBuilding*> bonusingBuildings;
std::vector<SpellID> possibleSpells, obligatorySpells;
std::vector<std::vector<SpellID> > spells; //spells[level] -> vector of spells, first will be available in guild
std::list<CCastleEvent> events;
std::pair<si32, si32> bonusValue;//var to store town bonuses (rampart = resources from mystic pond);
//////////////////////////////////////////////////////////////////////////
static std::vector<const CArtifact *> merchantArtifacts; //vector of artifacts available at Artifact merchant, NULLs possible (for making empty space when artifact is bought)
static std::vector<int> universitySkills;//skills for university of magic
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGDwelling&>(*this);
h & static_cast<IShipyard&>(*this);
h & static_cast<IMarket&>(*this);
h & name & builded & destroyed & identifier;
h & garrisonHero & visitingHero;
h & alignment & forbiddenBuildings & builtBuildings & bonusValue
& possibleSpells & obligatorySpells & spells & /*strInfo & */events & bonusingBuildings;
for (std::vector<CGTownBuilding*>::iterator i = bonusingBuildings.begin(); i!=bonusingBuildings.end(); i++)
(*i)->town = this;
h & town & townAndVis;
BONUS_TREE_DESERIALIZATION_FIX
vstd::erase_if(builtBuildings, [this](BuildingID building) -> bool
{
if(!town->buildings.count(building) || !town->buildings.at(building))
{
logGlobal->errorStream() << boost::format("#1444-like issue in CGTownInstance::serialize. From town %s at %s removing the bogus builtBuildings item %s")
% name % pos % building;
return true;
}
return false;
});
}
//////////////////////////////////////////////////////////////////////////
CBonusSystemNode *whatShouldBeAttached() override;
std::string nodeName() const override;
void updateMoraleBonusFromArmy() override;
void deserializationFix();
void recreateBuildingsBonuses();
bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, TPropagatorPtr &prop, int subtype = -1); //returns true if building is built and bonus has been added
bool addBonusIfBuilt(BuildingID building, Bonus::BonusType type, int val, int subtype = -1); //convienence version of above
void setVisitingHero(CGHeroInstance *h);
void setGarrisonedHero(CGHeroInstance *h);
const CArmedInstance *getUpperArmy() const; //garrisoned hero if present or the town itself
//////////////////////////////////////////////////////////////////////////
ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used
int3 getSightCenter() const override; //"center" tile from which the sight distance is calculated
int getSightRadious() const override; //returns sight distance
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
int getMarketEfficiency() const override; //=market count
bool allowsTrade(EMarketMode::EMarketMode mode) const;
std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const;
void setType(si32 ID, si32 subID);
void updateAppearance();
//////////////////////////////////////////////////////////////////////////
bool needsLastStack() const;
CGTownInstance::EFortLevel fortLevel() const;
int hallLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
int mageGuildLevel() const; // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
int getHordeLevel(const int & HID) const; //HID - 0 or 1; returns creature level or -1 if that horde structure is not present
int creatureGrowth(const int & level) const;
GrowthInfo getGrowthInfo(int level) const;
bool hasFort() const;
bool hasCapitol() const;
//checks if building is constructed and town has same subID
bool hasBuilt(BuildingID buildingID) const;
bool hasBuilt(BuildingID buildingID, int townID) const;
TResources dailyIncome() const; //calculates daily income of this town
int spellsAtLevel(int level, bool checkGuild) const; //levels are counted from 1 (1 - 5)
bool armedGarrison() const; //true if town has creatures in garrison or garrisoned hero
int getTownLevel() const;
void removeCapitols (PlayerColor owner) const;
void addHeroToStructureVisitors(const CGHeroInstance *h, si32 structureInstanceID) const; //hero must be visiting or garrisoned in town
CGTownInstance();
virtual ~CGTownInstance();
///IObjectInterface overrides
void newTurn() const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void onHeroLeave(const CGHeroInstance * h) const override;
void initObj() override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
protected:
void setPropertyDer(ui8 what, ui32 val) override;
};

View File

@ -0,0 +1,397 @@
#include "StdInc.h"
#include "CObjectClassesHandler.h"
#include "../filesystem/Filesystem.h"
#include "../filesystem/CBinaryReader.h"
#include "../lib/VCMI_Lib.h"
#include "../GameConstants.h"
#include "../StringConstants.h"
#include "../CGeneralTextHandler.h"
#include "../CModHandler.h"
#include "../JsonNode.h"
#include "CRewardableConstructor.h"
#include "CommonConstructors.h"
#include "MapObjects.h"
/*
* CObjectClassesHandler.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
*
*/
CObjectClassesHandler::CObjectClassesHandler()
{
#define SET_HANDLER_CLASS(STRING, CLASSNAME) handlerConstructors[STRING] = std::make_shared<CLASSNAME>;
#define SET_HANDLER(STRING, TYPENAME) handlerConstructors[STRING] = std::make_shared<CDefaultObjectTypeHandler<TYPENAME> >
// list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code
//Note: should be in sync with registerTypesMapObjectTypes function
SET_HANDLER_CLASS("configurable", CRewardableConstructor);
SET_HANDLER_CLASS("dwelling", CDwellingInstanceConstructor);
SET_HANDLER_CLASS("hero", CHeroInstanceConstructor);
SET_HANDLER_CLASS("town", CTownInstanceConstructor);
SET_HANDLER_CLASS("bank", CBankInstanceConstructor);
SET_HANDLER_CLASS("static", CObstacleConstructor);
SET_HANDLER_CLASS("", CObstacleConstructor);
SET_HANDLER("generic", CGObjectInstance);
SET_HANDLER("market", CGMarket);
SET_HANDLER("cartographer", CCartographer);
SET_HANDLER("artifact", CGArtifact);
SET_HANDLER("blackMarket", CGBlackMarket);
SET_HANDLER("boat", CGBoat);
SET_HANDLER("bonusingObject", CGBonusingObject);
SET_HANDLER("borderGate", CGBorderGate);
SET_HANDLER("borderGuard", CGBorderGuard);
SET_HANDLER("monster", CGCreature);
SET_HANDLER("denOfThieves", CGDenOfthieves);
SET_HANDLER("event", CGEvent);
SET_HANDLER("garrison", CGGarrison);
SET_HANDLER("heroPlaceholder", CGHeroPlaceholder);
SET_HANDLER("keymaster", CGKeymasterTent);
SET_HANDLER("lighthouse", CGLighthouse);
SET_HANDLER("magi", CGMagi);
SET_HANDLER("magicSpring", CGMagicSpring);
SET_HANDLER("magicWell", CGMagicWell);
SET_HANDLER("market", CGMarket);
SET_HANDLER("mine", CGMine);
SET_HANDLER("obelisk", CGObelisk);
SET_HANDLER("observatory", CGObservatory);
SET_HANDLER("onceVisitable", CGOnceVisitable);
SET_HANDLER("pandora", CGPandoraBox);
SET_HANDLER("pickable", CGPickable);
SET_HANDLER("prison", CGHeroInstance);
SET_HANDLER("questGuard", CGQuestGuard);
SET_HANDLER("resource", CGResource);
SET_HANDLER("scholar", CGScholar);
SET_HANDLER("seerHut", CGSeerHut);
SET_HANDLER("shipyard", CGShipyard);
SET_HANDLER("shrine", CGShrine);
SET_HANDLER("sign", CGSignBottle);
SET_HANDLER("siren", CGSirens);
SET_HANDLER("teleport", CGTeleport);
SET_HANDLER("university", CGUniversity);
SET_HANDLER("oncePerHero", CGVisitableOPH);
SET_HANDLER("oncePerWeek", CGVisitableOPW);
SET_HANDLER("witch", CGWitchHut);
#undef SET_HANDLER_CLASS
#undef SET_HANDLER
}
std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize)
{
CLegacyConfigParser parser("Data/Objects.txt");
size_t totalNumber = parser.readNumber(); // first line contains number of objects to read and nothing else
parser.endLine();
for (size_t i=0; i<totalNumber; i++)
{
ObjectTemplate templ;
templ.readTxt(parser);
parser.endLine();
std::pair<si32, si32> key(templ.id.num, templ.subid);
legacyTemplates.insert(std::make_pair(key, templ));
}
std::vector<JsonNode> ret(dataSize);// create storage for 256 objects
assert(dataSize == 256);
CLegacyConfigParser namesParser("Data/ObjNames.txt");
for (size_t i=0; i<256; i++)
{
ret[i]["name"].String() = namesParser.readString();
namesParser.endLine();
}
return ret;
}
/// selects preferred ID (or subID) for new object
template<typename Map>
si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID)
{
if (!fixedID.isNull() && fixedID.Float() < defaultID)
return fixedID.Float(); // H3M object with fixed ID
if (map.empty())
return defaultID; // no objects loaded, keep gap for H3M objects
if (map.rbegin()->first > defaultID)
return map.rbegin()->first + 1; // some modded objects loaded, return next available
return defaultID; // some H3M objects loaded, first modded found
}
void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj)
{
if (!handlerConstructors.count(obj->handlerName))
{
logGlobal->errorStream() << "Handler with name " << obj->handlerName << " was not found!";
return;
}
auto handler = handlerConstructors.at(obj->handlerName)();
handler->init(entry);
si32 id = selectNextID(entry["index"], obj->objects, 1000);
handler->setType(obj->id, id);
if (handler->getTemplates().empty())
{
auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id));
for (auto & templ : boost::make_iterator_range(range.first, range.second))
{
handler->addTemplate(templ.second);
}
legacyTemplates.erase(range.first, range.second);
}
obj->objects[id] = handler;
logGlobal->debugStream() << "Loaded object " << obj->id << ":" << id;
}
CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json)
{
auto obj = new ObjectContainter();
obj->name = json["name"].String();
obj->handlerName = json["handler"].String();
obj->base = json["base"];
obj->id = selectNextID(json["index"], objects, 256);
for (auto entry : json["types"].Struct())
{
loadObjectEntry(entry.second, obj);
}
return obj;
}
void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
{
auto object = loadFromJson(data);
objects[object->id] = object;
VLC->modh->identifiers.registerObject(scope, "object", name, object->id);
}
void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
{
auto object = loadFromJson(data);
assert(objects[index] == nullptr); // ensure that this id was not loaded before
objects[index] = object;
VLC->modh->identifiers.registerObject(scope, "object", name, object->id);
}
void CObjectClassesHandler::loadSubObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID)
{
config.setType(JsonNode::DATA_STRUCT); // ensure that input is not NULL
assert(objects.count(ID));
if (subID)
{
assert(objects.at(ID)->objects.count(subID.get()) == 0);
assert(config["index"].isNull());
config["index"].Float() = subID.get();
}
std::string oldMeta = config.meta; // FIXME: move into inheritNode?
JsonUtils::inherit(config, objects.at(ID)->base);
config.setMeta(oldMeta);
loadObjectEntry(config, objects[ID]);
}
void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID)
{
assert(objects.count(ID));
assert(objects.at(ID)->objects.count(subID));
objects.at(ID)->objects.erase(subID);
}
std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const
{
return std::vector<bool>(); //TODO?
}
TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const
{
if (objects.count(type))
{
if (objects.at(type)->objects.count(subtype))
return objects.at(type)->objects.at(subtype);
}
logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype;
assert(0); // FIXME: throw error?
return nullptr;
}
std::set<si32> CObjectClassesHandler::knownObjects() const
{
std::set<si32> ret;
for (auto entry : objects)
ret.insert(entry.first);
return ret;
}
std::set<si32> CObjectClassesHandler::knownSubObjects(si32 primaryID) const
{
std::set<si32> ret;
if (objects.count(primaryID))
{
for (auto entry : objects.at(primaryID)->objects)
ret.insert(entry.first);
}
return ret;
}
void CObjectClassesHandler::beforeValidate(JsonNode & object)
{
for (auto & entry : object["types"].Struct())
{
JsonUtils::inherit(entry.second, object["base"]);
for (auto & templ : entry.second["templates"].Struct())
{
JsonUtils::inherit(templ.second, entry.second["base"]);
}
}
}
void CObjectClassesHandler::afterLoadFinalization()
{
for (auto entry : objects)
{
for (auto obj : entry.second->objects)
{
obj.second->afterLoadFinalization();
if (obj.second->getTemplates().empty())
logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first;
}
}
}
std::string CObjectClassesHandler::getObjectName(si32 type) const
{
assert(objects.count(type));
return objects.at(type)->name;
}
void AObjectTypeHandler::setType(si32 type, si32 subtype)
{
this->type = type;
this->subtype = subtype;
}
static ui32 loadJsonOrMax(const JsonNode & input)
{
if (input.isNull())
return std::numeric_limits<ui32>::max();
else
return input.Float();
}
void AObjectTypeHandler::init(const JsonNode & input)
{
base = input["base"];
if (!input["rmg"].isNull())
{
rmgInfo.value = input["rmg"]["value"].Float();
rmgInfo.mapLimit = loadJsonOrMax(input["rmg"]["mapLimit"]);
rmgInfo.zoneLimit = loadJsonOrMax(input["rmg"]["zoneLimit"]);
rmgInfo.rarity = input["rmg"]["rarity"].Float();
} // else block is not needed - set in constructor
for (auto entry : input["templates"].Struct())
{
entry.second.setType(JsonNode::DATA_STRUCT);
JsonUtils::inherit(entry.second, base);
ObjectTemplate tmpl;
tmpl.id = Obj(type);
tmpl.subid = subtype;
tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template?
tmpl.readJson(entry.second);
templates.push_back(tmpl);
}
initTypeData(input);
}
bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const
{
return false; // by default there are no overrides
}
void AObjectTypeHandler::initTypeData(const JsonNode & input)
{
}
void AObjectTypeHandler::addTemplate(ObjectTemplate templ)
{
templ.id = Obj(type);
templ.subid = subtype;
templates.push_back(templ);
}
void AObjectTypeHandler::addTemplate(JsonNode config)
{
config.setType(JsonNode::DATA_STRUCT); // ensure that input is not null
JsonUtils::inherit(config, base);
ObjectTemplate tmpl;
tmpl.id = Obj(type);
tmpl.subid = subtype;
tmpl.stringID = ""; // TODO?
tmpl.readJson(config);
addTemplate(tmpl);
}
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const
{
return templates;
}
std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(si32 terrainType) const// FIXME: replace with ETerrainType
{
std::vector<ObjectTemplate> templates = getTemplates();
std::vector<ObjectTemplate> filtered;
std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj)
{
return obj.canBePlacedAt(ETerrainType(terrainType));
});
// H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here
// Perhaps we should re-define faulty templates and remove this workaround (already done for resources)
if (type == Obj::ARTIFACT || type == Obj::MONSTER)
return templates;
else
return filtered;
}
boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const
{
std::vector<ObjectTemplate> ret = getTemplates(terrainType);
for (auto & tmpl : ret)
{
if (objectFilter(object, tmpl))
return tmpl;
}
return boost::optional<ObjectTemplate>();
}
const RandomMapInfo & AObjectTypeHandler::getRMGInfo()
{
return rmgInfo;
}
bool AObjectTypeHandler::isStaticObject()
{
return false; // most of classes are not static
}
void AObjectTypeHandler::afterLoadFinalization()
{
}

View File

@ -0,0 +1,218 @@
#pragma once
#include "ObjectTemplate.h"
#include "../GameConstants.h"
#include "../ConstTransitivePtr.h"
#include "../IHandlerBase.h"
/*
* CObjectClassesHandler.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 JsonNode;
class CRandomGenerator;
/// Structure that describes placement rules for this object in random map
struct RandomMapInfo
{
/// How valuable this object is, 1k = worthless, 10k = Utopia-level
ui32 value;
/// How many of such objects can be placed on map, 0 = object can not be placed by RMG
ui32 mapLimit;
/// How many of such objects can be placed in one zone, 0 = unplaceable
ui32 zoneLimit;
/// Rarity of object, 5 = extremely rare, 100 = common
ui32 rarity;
RandomMapInfo():
value(0),
mapLimit(0),
zoneLimit(0),
rarity(0)
{}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & value & mapLimit & zoneLimit & rarity;
}
};
class IObjectInfo
{
public:
struct CArmyStructure
{
ui32 totalStrength;
ui32 shootersStrength;
ui32 flyersStrength;
ui32 walkersStrength;
CArmyStructure() :
totalStrength(0),
shootersStrength(0),
flyersStrength(0),
walkersStrength(0)
{}
bool operator <(const CArmyStructure & other)
{
return this->totalStrength < other.totalStrength;
}
};
/// Returns possible composition of guards. Actual guards would be
/// somewhere between these two values
virtual CArmyStructure minGuards() const { return CArmyStructure(); }
virtual CArmyStructure maxGuards() const { return CArmyStructure(); }
virtual bool givesResources() const { return false; }
virtual bool givesExperience() const { return false; }
virtual bool givesMana() const { return false; }
virtual bool givesMovement() const { return false; }
virtual bool givesPrimarySkills() const { return false; }
virtual bool givesSecondarySkills() const { return false; }
virtual bool givesArtifacts() const { return false; }
virtual bool givesCreatures() const { return false; }
virtual bool givesSpells() const { return false; }
virtual bool givesBonuses() const { return false; }
};
class CGObjectInstance;
class AObjectTypeHandler : public boost::noncopyable
{
RandomMapInfo rmgInfo;
si32 type;
si32 subtype;
JsonNode base; /// describes base template
std::vector<ObjectTemplate> templates;
protected:
virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const;
/// initialization for classes that inherit this one
virtual void initTypeData(const JsonNode & input);
public:
virtual ~AObjectTypeHandler(){}
void setType(si32 type, si32 subtype);
/// loads generic data from Json structure and passes it towards type-specific constructors
void init(const JsonNode & input);
void addTemplate(ObjectTemplate templ);
void addTemplate(JsonNode config);
/// returns all templates matching parameters
std::vector<ObjectTemplate> getTemplates() const;
std::vector<ObjectTemplate> getTemplates(si32 terrainType) const;
/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle)
/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server)
boost::optional<ObjectTemplate> getOverride(si32 terrainType, const CGObjectInstance * object) const;
const RandomMapInfo & getRMGInfo();
virtual bool isStaticObject();
virtual void afterLoadFinalization();
/// Creates object and set up core properties (like ID/subID). Object is NOT initialized
/// to allow creating objects before game start (e.g. map loading)
virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0;
/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily
/// This should set remaining properties, including randomized or depending on map
virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0;
/// Returns object configuration, if available. Othervice returns NULL
virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const = 0;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & type & subtype & templates & rmgInfo;
}
};
typedef std::shared_ptr<AObjectTypeHandler> TObjectTypeHandler;
class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase
{
/// Small internal structure that contains information on specific group of objects
/// (creating separate entity is overcomplicating at least at this point)
struct ObjectContainter
{
si32 id;
std::string name; // human-readable name
std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map
JsonNode base;
std::map<si32, TObjectTypeHandler> objects;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & name & handlerName & base & objects;
}
};
typedef std::multimap<std::pair<si32, si32>, ObjectTemplate> TTemplatesContainer;
/// list of object handlers, each of them handles only one type
std::map<si32, ObjectContainter * > objects;
/// map that is filled during contruction with all known handlers. Not serializeable due to usage of std::function
std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors;
/// container with H3 templates, used only during loading, no need to serialize it
TTemplatesContainer legacyTemplates;
void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj);
ObjectContainter * loadFromJson(const JsonNode & json);
public:
CObjectClassesHandler();
std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
void loadObject(std::string scope, std::string name, const JsonNode & data) override;
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override;
void loadSubObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>());
void removeSubObject(si32 ID, si32 subID);
void beforeValidate(JsonNode & object) override;
void afterLoadFinalization() override;
std::vector<bool> getDefaultAllowed() const override;
/// Queries to detect loaded objects
std::set<si32> knownObjects() const;
std::set<si32> knownSubObjects(si32 primaryID) const;
/// returns handler for specified object (ID-based). ObjectHandler keeps ownership
TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const;
std::string getObjectName(si32 type) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & objects;
}
};

View File

@ -0,0 +1,497 @@
/*
* CObjectHandler.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 "CObjectHandler.h"
#include "../NetPacks.h"
#include "../CGeneralTextHandler.h"
#include "../CHeroHandler.h"
#include "../CSoundBase.h"
#include "CObjectClassesHandler.h"
using namespace boost::assign;
IGameCallback * IObjectInterface::cb = nullptr;
///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);
}
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 ObjectInstanceID heroID, const ui32 txtID, const ui16 soundID)
{
const PlayerColor playerID = IObjectInterface::cb->getOwner(heroID);
showInfoDialog(playerID,txtID,soundID);
}*/
static void showInfoDialog(const CGHeroInstance* h, const ui32 txtID, const ui16 soundID)
{
const PlayerColor playerID = h->getOwner();
showInfoDialog(playerID,txtID,soundID);
}
static std::string & visitedTxt(const bool visited)
{
int id = visited ? 352 : 353;
return VLC->generaltexth->allTexts[id];
}
///IObjectInterface
void IObjectInterface::onHeroVisit(const CGHeroInstance * h) const
{}
void IObjectInterface::onHeroLeave(const CGHeroInstance * h) const
{}
void IObjectInterface::newTurn () const
{}
IObjectInterface::~IObjectInterface()
{}
IObjectInterface::IObjectInterface()
{}
void IObjectInterface::initObj()
{}
void IObjectInterface::setProperty( ui8 what, ui32 val )
{}
bool IObjectInterface::wasVisited (PlayerColor player) const
{
return false;
}
bool IObjectInterface::wasVisited (const CGHeroInstance * h) const
{
return false;
}
void IObjectInterface::postInit()
{}
void IObjectInterface::preInit()
{}
void IObjectInterface::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
{}
void IObjectInterface::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{}
void IObjectInterface::garrisonDialogClosed(const CGHeroInstance *hero) const
{}
void IObjectInterface::heroLevelUpDone(const CGHeroInstance *hero) const
{}
CObjectHandler::CObjectHandler()
{
logGlobal->traceStream() << "\t\tReading resources prices ";
const JsonNode config2(ResourceID("config/resources.json"));
for(const JsonNode &price : config2["resources_prices"].Vector())
{
resVals.push_back(price.Float());
}
logGlobal->traceStream() << "\t\tDone loading resource prices!";
}
PlayerColor CGObjectInstance::getOwner() const
{
//if (state)
// return state->owner;
//else
return tempOwner; //won't have owner
}
CGObjectInstance::CGObjectInstance():
pos(-1,-1,-1),
ID(Obj::NO_OBJ),
subID(-1),
tempOwner(PlayerColor::UNFLAGGABLE),
blockVisit(false)
{
}
CGObjectInstance::~CGObjectInstance()
{
//if (state)
// delete state;
//state=nullptr;
}
const std::string & CGObjectInstance::getHoverText() const
{
return hoverName;
}
void CGObjectInstance::setOwner(PlayerColor ow)
{
//if (state)
// state->owner = ow;
//else
tempOwner = ow;
}
int CGObjectInstance::getWidth() const//returns width of object graphic in tiles
{
return appearance.getWidth();
}
int CGObjectInstance::getHeight() const //returns height of object graphic in tiles
{
return appearance.getHeight();
}
bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles)
{
return appearance.isVisitableAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::blockingAt(int x, int y) const
{
return appearance.isBlockedAt(pos.x - x, pos.y - y);
}
bool CGObjectInstance::coveringAt(int x, int y) const
{
return appearance.isVisibleAt(pos.x - x, pos.y - y);
}
std::set<int3> CGObjectInstance::getBlockedPos() const
{
std::set<int3> ret;
for(int w=0; w<getWidth(); ++w)
{
for(int h=0; h<getHeight(); ++h)
{
if (appearance.isBlockedAt(w, h))
ret.insert(int3(pos.x - w, pos.y - h, pos.z));
}
}
return ret;
}
std::set<int3> CGObjectInstance::getBlockedOffsets() const
{
std::set<int3> ret;
for(int w=0; w<getWidth(); ++w)
{
for(int h=0; h<getHeight(); ++h)
{
if (appearance.isBlockedAt(w, h))
ret.insert(int3(-w, -h, 0));
}
}
return ret;
}
bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const //screen printing priority comparing
{
if (appearance.printPriority != cmp.appearance.printPriority)
return appearance.printPriority > cmp.appearance.printPriority;
if(pos.y != cmp.pos.y)
return pos.y < cmp.pos.y;
if(cmp.ID==Obj::HERO && ID!=Obj::HERO)
return true;
if(cmp.ID!=Obj::HERO && ID==Obj::HERO)
return false;
if(!isVisitable() && cmp.isVisitable())
return true;
if(!cmp.isVisitable() && isVisitable())
return false;
if(this->pos.x<cmp.pos.x)
return true;
return false;
}
void CGObjectInstance::setType(si32 ID, si32 subID)
{
const TerrainTile &tile = cb->gameState()->map->getTile(visitablePos());
this->ID = Obj(ID);
this->subID = subID;
//recalculate blockvis tiles - new appearance might have different blockmap than before
cb->gameState()->map->removeBlockVisTiles(this, true);
auto handler = VLC->objtypeh->getHandlerFor(ID, subID);
appearance = handler->getTemplates(tile.terType).at(0);
cb->gameState()->map->addBlockVisTiles(this);
}
void CGObjectInstance::initObj()
{
switch(ID)
{
case Obj::TAVERN:
blockVisit = true;
break;
}
}
void CGObjectInstance::setProperty( ui8 what, ui32 val )
{
switch(what)
{
case ObjProperty::OWNER:
tempOwner = PlayerColor(val);
break;
case ObjProperty::BLOCKVIS:
blockVisit = val;
break;
case ObjProperty::ID:
ID = Obj(val);
break;
case ObjProperty::SUBID:
subID = val;
break;
}
setPropertyDer(what, val);
}
void CGObjectInstance::setPropertyDer( ui8 what, ui32 val )
{}
int3 CGObjectInstance::getSightCenter() const
{
//return vistiable tile if possible
for(int i=0; i < 8; i++)
for(int j=0; j < 6; j++)
if(visitableAt(i,j))
return(pos + int3(i-7, j-5, 0));
return pos;
}
int CGObjectInstance::getSightRadious() const
{
return 3;
}
void CGObjectInstance::getSightTiles(std::unordered_set<int3, ShashInt3> &tiles) const //returns reference to the set
{
cb->getTilesInRange(tiles, getSightCenter(), getSightRadious(), tempOwner, 1);
}
void CGObjectInstance::hideTiles(PlayerColor ourplayer, int radius) const
{
for (auto i = cb->gameState()->teams.begin(); i != cb->gameState()->teams.end(); i++)
{
if ( !vstd::contains(i->second.players, ourplayer ))//another team
{
for (auto & elem : i->second.players)
if ( cb->getPlayer(elem)->status == EPlayerStatus::INGAME )//seek for living player (if any)
{
FoWChange fw;
fw.mode = 0;
fw.player = elem;
cb->getTilesInRange (fw.tiles, pos, radius, (elem), -1);
cb->sendAndApply (&fw);
break;
}
}
}
}
int3 CGObjectInstance::getVisitableOffset() const
{
for(int y = 0; y < appearance.getHeight(); y++)
for (int x = 0; x < appearance.getWidth(); x++)
if (appearance.isVisitableAt(x, y))
return int3(x,y,0);
logGlobal->warnStream() << "Warning: getVisitableOffset called on non-visitable obj!";
return int3(0,0,0);
}
void CGObjectInstance::getNameVis( std::string &hname ) const
{
const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
hname = VLC->objtypeh->getObjectName(ID);
if(h)
{
const bool visited = h->hasBonusFrom(Bonus::OBJECT,ID);
hname + " " + visitedTxt(visited);
}
}
void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const
{
GiveBonus gbonus;
gbonus.bonus.type = Bonus::NONE;
gbonus.id = heroID.getNum();
gbonus.bonus.duration = duration;
gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.sid = ID;
cb->giveHeroBonus(&gbonus);
}
void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const
{
switch(ID)
{
case Obj::HILL_FORT:
{
openWindow(OpenWindow::HILL_FORT_WINDOW,id.getNum(),h->id.getNum());
}
break;
case Obj::SANCTUARY:
{
//You enter the sanctuary and immediately feel as if a great weight has been lifted off your shoulders. You feel safe here.
showInfoDialog(h,114,soundBase::GETPROTECTION);
}
break;
case Obj::TAVERN:
{
openWindow(OpenWindow::TAVERN_WINDOW,h->id.getNum(),id.getNum());
}
break;
}
}
ui8 CGObjectInstance::getPassableness() const
{
return 0;
}
int3 CGObjectInstance::visitablePos() const
{
return pos - getVisitableOffset();
}
bool CGObjectInstance::isVisitable() const
{
return appearance.isVisitable();
}
bool CGObjectInstance::passableFor(PlayerColor color) const
{
return getPassableness() & 1<<color.getNum();
}
CGObjectInstanceBySubIdFinder::CGObjectInstanceBySubIdFinder(CGObjectInstance * obj) : obj(obj)
{
}
bool CGObjectInstanceBySubIdFinder::operator()(CGObjectInstance * obj) const
{
return this->obj->subID == obj->subID;
}
int3 IBoatGenerator::bestLocation() const
{
std::vector<int3> offsets;
getOutOffsets(offsets);
for (auto & offset : offsets)
{
if (const TerrainTile *tile = IObjectInterface::cb->getTile(o->pos + offset, false)) //tile is in the map
{
if (tile->terType == ETerrainType::WATER && (!tile->blocked || tile->blockingObjects.front()->ID == 8)) //and is water and is not blocked or is blocked by boat
return o->pos + offset;
}
}
return int3 (-1,-1,-1);
}
IBoatGenerator::EGeneratorState IBoatGenerator::shipyardStatus() const
{
int3 tile = bestLocation();
const TerrainTile *t = IObjectInterface::cb->getTile(tile);
if(!t)
return TILE_BLOCKED; //no available water
else if(!t->blockingObjects.size())
return GOOD; //OK
else if(t->blockingObjects.front()->ID == Obj::BOAT)
return BOAT_ALREADY_BUILT; //blocked with boat
else
return TILE_BLOCKED; //blocked
}
int IBoatGenerator::getBoatType() const
{
//We make good ships by default
return 1;
}
IBoatGenerator::IBoatGenerator(const CGObjectInstance *O)
: o(O)
{
}
void IBoatGenerator::getProblemText(MetaString &out, const CGHeroInstance *visitor) const
{
switch(shipyardStatus())
{
case BOAT_ALREADY_BUILT:
out.addTxt(MetaString::GENERAL_TXT, 51);
break;
case TILE_BLOCKED:
if(visitor)
{
out.addTxt(MetaString::GENERAL_TXT, 134);
out.addReplacement(visitor->name);
}
else
out.addTxt(MetaString::ADVOB_TXT, 189);
break;
case NO_WATER:
logGlobal->errorStream() << "Shipyard without water!!! " << o->pos << "\t" << o->id;
return;
}
}
void IShipyard::getBoatCost( std::vector<si32> &cost ) const
{
cost.resize(GameConstants::RESOURCE_QUANTITY);
cost[Res::WOOD] = 10;
cost[Res::GOLD] = 1000;
}
IShipyard::IShipyard(const CGObjectInstance *O)
: IBoatGenerator(O)
{
}
IShipyard * IShipyard::castFrom( CGObjectInstance *obj )
{
if(!obj)
return nullptr;
if(obj->ID == Obj::TOWN)
{
return static_cast<CGTownInstance*>(obj);
}
else if(obj->ID == Obj::SHIPYARD)
{
return static_cast<CGShipyard*>(obj);
}
else
{
return nullptr;
}
}
const IShipyard * IShipyard::castFrom( const CGObjectInstance *obj )
{
return castFrom(const_cast<CGObjectInstance*>(obj));
}

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