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

Finally shattered CObjectHandler.cpp into tiny bits

- This file is now split into multiple smaller files in mapObjects
directory
- CObjectHandler itself now contains only core classes (Handler itself,
CGObject and interfaces)
- Cleaned up excessive #include's through whole project
This commit is contained in:
Ivan Savenko 2014-06-05 19:52:14 +03:00
parent 0afdfa529c
commit 652ceb2bde
71 changed files with 7730 additions and 7354 deletions

View File

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

View File

@ -5,7 +5,7 @@
#include "../../lib/CCreatureHandler.h"
#include "../../lib/CTownHandler.h"
#include "../../lib/CSpellHandler.h"
#include "../../lib/mapObjects/CObjectHandler.h"
//#include "../../lib/mapObjects/CObjectHandler.h"
#include "../../lib/Connection.h"
#include "../../lib/CGameState.h"
#include "../../lib/mapping/CMap.h"
@ -200,4 +200,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,7 +2,7 @@
#include "Fuzzy.h"
#include <limits>
#include "../../lib/mapObjects/CObjectHandler.h"
#include "../../lib/mapObjects/MapObjects.h"
#include "../../lib/CCreatureHandler.h"
#include "../../lib/VCMI_Lib.h"
#include "../../CCallback.h"

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@
#include "lib/mapObjects/CObjectClassesHandler.h"
#include "lib/CGeneralTextHandler.h"
#include "lib/CHeroHandler.h"
#include "lib/mapObjects/CObjectHandler.h"
//#include "lib/mapObjects/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/mapObjects/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/mapObjects/CObjectHandler.h"
#include "../lib/mapObjects/CGHeroInstance.h"
#include "../lib/CTownHandler.h"
#include "../lib/mapping/CMap.h"
#include "../lib/JsonNode.h"

View File

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

View File

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

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/mapObjects/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
@ -953,4 +953,4 @@ void CHeroItem::onArtChange(int tabIndex)
//redraw item after background change
if (active)
redraw();
}
}

View File

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

View File

@ -1,5 +1,5 @@
#include "StdInc.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "CAdvmapInterface.h"
#include "battle/CBattleInterface.h"
#include "battle/CBattleInterfaceClasses.h"
@ -21,7 +21,7 @@
#include "../lib/CArtHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/Connection.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CTownHandler.h"

View File

@ -11,11 +11,11 @@
#include "gui/CCursorHandler.h"
#include "CAnimation.h"
#include "CDefHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/mapping/CCampaignHandler.h"
#include "../lib/CCreatureHandler.h"
#include "../lib/JsonNode.h"

View File

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

View File

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

View File

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

View File

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

View File

@ -12,13 +12,13 @@
#include "../CCallback.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CCreatureHandler.h"
#include "CBitmapHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/CGameState.h"
#include "../lib/JsonNode.h"
#include "../lib/vcmi_endian.h"

View File

@ -9,9 +9,9 @@
#include "CGameInfo.h"
#include "../lib/Connection.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/VCMI_Lib.h"
#include "../lib/mapping/CMap.h"
#include "../lib/VCMIDirs.h"

View File

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

View File

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

View File

@ -14,12 +14,12 @@
#include "CBitmapHandler.h"
#include "gui/SDL_Extensions.h"
#include "CGameInfo.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/mapObjects/CObjectHandler.h"
#include "../lib/mapping/CMap.h"
#include "CDefHandler.h"
#include "../lib/CConfigHandler.h"

View File

@ -4,12 +4,14 @@
#include "BattleHex.h"
#include "HeroBonus.h"
#include "CCreatureSet.h"
#include "mapObjects/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 "mapObjects/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

View File

@ -9,6 +9,8 @@
#include "CModHandler.h"
#include "StringConstants.h"
#include "mapObjects/CObjectClassesHandler.h"
using namespace boost::assign;
/*

View File

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

View File

@ -14,7 +14,7 @@
#include "IGameCallback.h"
#include "ResourceSet.h"
#include "int3.h"
#include "mapObjects/CObjectHandler.h"
//#include "mapObjects/CObjectHandler.h"
#include "CRandomGenerator.h"
/*

View File

@ -13,6 +13,8 @@
#include "mapObjects/CObjectHandler.h" //for hero specialty
#include <math.h>
#include "mapObjects/CObjectClassesHandler.h"
/*
* CHeroHandler.cpp, part of VCMI engine
*

View File

@ -6,19 +6,6 @@ include_directories(${Boost_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}
set(lib_SRCS
StdInc.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
filesystem/AdapterLoaders.cpp
filesystem/CCompressedStream.cpp
@ -32,10 +19,18 @@ set(lib_SRCS
filesystem/Filesystem.cpp
filesystem/ResourceID.cpp
mapObjects/CGArmedInstance.cpp
mapObjects/CGBank.cpp
mapObjects/CGHeroInstance.cpp
mapObjects/CGMarket.cpp
mapObjects/CGPandoraBox.cpp
mapObjects/CGTownInstance.cpp
mapObjects/CObjectClassesHandler.cpp
mapObjects/CObjectHandler.cpp
mapObjects/CQuest.cpp
mapObjects/CRewardableConstructor.cpp
mapObjects/CRewardableObject.cpp
mapObjects/MiscObjects.cpp
mapObjects/ObjectTemplate.cpp
logging/CBasicLogConfigurator.cpp
@ -85,6 +80,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
@ -93,6 +102,8 @@ set(lib_HEADERS
filesystem/CInputStream.h
filesystem/ISimpleResourceLoader.h
mapObjects/MapObjects.h
AI_Base.h
CondSh.h
ConstTransitivePtr.h

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 "mapObjects/CObjectHandler.h" //for CArmedInstance
#include "mapObjects/CGHeroInstance.h"
#include "mapping/CCampaignHandler.h" //for CCampaignState
#include "rmg/CMapGenerator.h" // for CMapGenOptions

View File

@ -17,6 +17,7 @@
#include "CBonusTypeHandler.h"
#include "Connection.h" // for SAVEGAME_MAGIC
#include "mapObjects/CObjectClassesHandler.h"
void CPrivilagedInfoCallback::getFreeTiles (std::vector<int3> &tiles) const
{

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"

View File

@ -0,0 +1,128 @@
/*
* 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 "CGArmedInstance.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"
/*
* CObjectHandler.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);
}
};

443
lib/mapObjects/CGBank.cpp Normal file
View File

@ -0,0 +1,443 @@
/*
* 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 "CGBank.h"
#include "NetPacks.h"
#include "CGeneralTextHandler.h"
#include "../client/CSoundBase.h"
using namespace boost::assign;
///helpers
static std::string & visitedTxt(const bool visited)
{
int id = visited ? 352 : 353;
return VLC->generaltexth->allTexts[id];
}
void CBank::initObj()
{
index = VLC->objh->bankObjToIndex(this);
bc = nullptr;
daycounter = 0;
multiplier = 1;
}
const std::string & CBank::getHoverText() const
{
bool visited = (bc == nullptr);
hoverName = VLC->objh->creBanksNames[index] + " " + visitedTxt(visited);
return hoverName;
}
void CBank::reset(ui16 var1) //prevents desync
{
ui8 chance = 0;
for (auto & elem : VLC->objh->banksInfo[index])
{
if (var1 < (chance += elem->chance))
{
bc = elem;
break;
}
}
artifacts.clear();
}
void CBank::initialize() const
{
cb->setObjProperty(id, ObjProperty::BANK_RESET, cb->gameState()->getRandomGenerator().nextInt()); //synchronous reset
for (ui8 i = 0; i <= 3; i++)
{
for (ui8 n = 0; n < bc->artifacts[i]; n++)
{
CArtifact::EartClass artClass;
switch(i)
{
case 0: artClass = CArtifact::ART_TREASURE; break;
case 1: artClass = CArtifact::ART_MINOR; break;
case 2: artClass = CArtifact::ART_MAJOR; break;
case 3: artClass = CArtifact::ART_RELIC; break;
default: assert(0); continue;
}
int artID = VLC->arth->pickRandomArtifact(cb->gameState()->getRandomGenerator(), artClass);
cb->setObjProperty(id, ObjProperty::BANK_ADD_ARTIFACT, artID);
}
}
cb->setObjProperty(id, ObjProperty::BANK_INIT_ARMY, cb->gameState()->getRandomGenerator().nextInt()); //get army
}
void CBank::setPropertyDer (ui8 what, ui32 val)
/// random values are passed as arguments and processed identically on all clients
{
switch (what)
{
case ObjProperty::BANK_DAYCOUNTER: //daycounter
if (val == 0)
daycounter = 1; //yes, 1
else
daycounter++;
break;
case ObjProperty::BANK_MULTIPLIER: //multiplier, in percent
multiplier = val / 100.0;
break;
case 13: //bank preset
bc = VLC->objh->banksInfo[index][val];
break;
case ObjProperty::BANK_RESET:
reset (val%100);
break;
case ObjProperty::BANK_CLEAR_CONFIG:
bc = nullptr;
break;
case ObjProperty::BANK_CLEAR_ARTIFACTS: //remove rewards from Derelict Ship
artifacts.clear();
break;
case ObjProperty::BANK_INIT_ARMY: //set ArmedInstance army
{
int upgraded = 0;
if (val%100 < bc->upgradeChance) //once again anti-desync
upgraded = 1;
switch (bc->guards.size())
{
case 1:
for (int i = 0; i < 4; ++i)
setCreature (SlotID(i), bc->guards[0].first, bc->guards[0].second / 5 );
setCreature (SlotID(4), CreatureID(bc->guards[0].first + upgraded), bc->guards[0].second / 5 );
break;
case 4:
{
if (bc->guards.back().second) //all stacks are present
{
for (auto & elem : bc->guards)
{
setCreature (SlotID(stacksCount()), elem.first, elem.second);
}
}
else if (bc->guards[2].second)//Wraiths are present, split two stacks in Crypt
{
setCreature (SlotID(0), bc->guards[0].first, bc->guards[0].second / 2 );
setCreature (SlotID(1), bc->guards[1].first, bc->guards[1].second / 2);
setCreature (SlotID(2), CreatureID(bc->guards[2].first + upgraded), bc->guards[2].second);
setCreature (SlotID(3), bc->guards[1].first, bc->guards[1].second / 2 );
setCreature (SlotID(4), bc->guards[0].first, bc->guards[0].second - (bc->guards[0].second / 2) );
}
else //split both stacks
{
for (int i = 0; i < 3; ++i) //skellies
setCreature (SlotID(2*i), bc->guards[0].first, bc->guards[0].second / 3);
for (int i = 0; i < 2; ++i) //zombies
setCreature (SlotID(2*i+1), bc->guards[1].first, bc->guards[1].second / 2);
}
}
break;
default:
logGlobal->warnStream() << "Error: Unexpected army data: " << bc->guards.size() <<" items found";
return;
}
}
break;
case ObjProperty::BANK_ADD_ARTIFACT: //add Artifact
{
artifacts.push_back (val);
break;
}
}
}
void CBank::newTurn() const
{
if (bc == nullptr)
{
if (cb->getDate() == 1)
initialize(); //initialize on first day
else if (daycounter >= 28 && (subID < 13 || subID > 16)) //no reset for Emissaries
{
initialize();
cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 0); //daycounter 0
if (ID == Obj::DERELICT_SHIP && cb->getDate() > 1)
{
cb->setObjProperty (id, ObjProperty::BANK_MULTIPLIER, 0);//ugly hack to make derelict ships usable only once
cb->setObjProperty (id, ObjProperty::BANK_CLEAR_ARTIFACTS, 0);
}
}
else
cb->setObjProperty (id, ObjProperty::BANK_DAYCOUNTER, 1); //daycounter++
}
}
bool CBank::wasVisited (PlayerColor player) const
{
return !bc;
}
void CBank::onHeroVisit (const CGHeroInstance * h) const
{
if (bc)
{
int banktext = 0;
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;
}
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundBase::ROGUE;
bd.text.addTxt(MetaString::ADVOB_TXT,banktext);
if (ID == Obj::CREATURE_BANK)
bd.text.addReplacement(VLC->objh->creBanksNames[index]);
cb->showBlockingDialog (&bd);
}
else
{
InfoWindow iw;
iw.soundID = soundBase::GRAVEYARD;
iw.player = h->getOwner();
if (ID == Obj::CRYPT) //morale penalty for empty Crypt
{
GiveBonus gbonus;
gbonus.id = h->id.getNum();
gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.sid = ID;
gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[98];
gbonus.bonus.type = Bonus::MORALE;
gbonus.bonus.val = -1;
cb->giveHeroBonus(&gbonus);
iw.text << VLC->generaltexth->advobtxt[120];
iw.components.push_back (Component (Component::MORALE, 0 , -1, 0));
}
else
{
iw.text << VLC->generaltexth->advobtxt[33];
iw.text.addReplacement(VLC->objh->creBanksNames[index]);
}
cb->showInfoDialog(&iw);
}
}
void CBank::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
{
if (result.winner == 0)
{
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 (multiplier)
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->resources.size() != 0)
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->resources.size())
textID = 124;
else
textID = 123;
break;
}
//grant resources
if (textID != 42) //empty derelict ship gives no cash
{
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 : 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)
{
iw.text.addReplacement(MetaString::CRE_PL_NAMES, result.casualties[1].begin()->first);
iw.text.addReplacement(loot.buildList());
}
cb->showInfoDialog(&iw);
}
loot.clear();
iw.components.clear();
iw.text.clear();
//grant creatures
CCreatureSet ourArmy;
for (auto it = bc->creatures.cbegin(); it != bc->creatures.cend(); it++)
{
SlotID slot = ourArmy.getSlotFor(it->first);
ourArmy.addToSlot(slot, it->first, it->second);
}
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_CONFIG, 0); //bc = nullptr
}
}
void CBank::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
if (answer)
{
cb->startBattleI(hero, this, true);
}
}
void CGPyramid::initObj()
{
std::vector<SpellID> available;
cb->getAllowedSpells (available, 5);
if (available.size())
{
bc = VLC->objh->banksInfo[21].front(); //TODO: remove hardcoded value?
spell = *RandomGeneratorUtil::nextItem(available, cb->gameState()->getRandomGenerator());
}
else
{
logGlobal->errorStream() <<"No spells available for Pyramid! Object set to empty.";
}
setPropertyDer(ObjProperty::BANK_INIT_ARMY, cb->gameState()->getRandomGenerator().nextInt()); //set guards at game start
}
const std::string & CGPyramid::getHoverText() const
{
hoverName = VLC->objh->creBanksNames[21]+ " " + visitedTxt((bc==nullptr));
return hoverName;
}
void CGPyramid::onHeroVisit (const CGHeroInstance * h) const
{
if (bc)
{
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundBase::MYSTERY;
bd.text << VLC->generaltexth->advobtxt[105];
cb->showBlockingDialog(&bd);
}
else
{
InfoWindow iw;
iw.player = h->getOwner();
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);
cb->showInfoDialog(&iw);
}
}
void CGPyramid::battleFinished(const CGHeroInstance *hero, const BattleResult &result) const
{
if (result.winner == 0)
{
InfoWindow iw;
iw.player = hero->getOwner();
iw.text.addTxt (MetaString::ADVOB_TXT, 106);
iw.text.addTxt (MetaString::SPELL_NAME, spell);
if (!hero->getArt(ArtifactPosition::SPELLBOOK))
iw.text.addTxt (MetaString::ADVOB_TXT, 109); //no spellbook
else if (hero->getSecSkillLevel(SecondarySkill::WISDOM) < 3)
iw.text.addTxt (MetaString::ADVOB_TXT, 108); //no expert Wisdom
else
{
std::set<SpellID> spells;
spells.insert (SpellID(spell));
cb->changeSpells (hero, true, spells);
iw.components.push_back(Component (Component::SPELL, spell, 0, 0));
}
cb->showInfoDialog(&iw);
cb->setObjProperty (id, ObjProperty::BANK_CLEAR_CONFIG, 0);
}
}

59
lib/mapObjects/CGBank.h Normal file
View File

@ -0,0 +1,59 @@
#pragma once
#include "CObjectHandler.h"
#include "CGArmedInstance.h"
/*
* CObjectHandler.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 CBank : public CArmedInstance
{
public:
int index; //banks have unusal numbering - see ZCRBANK.txt and initObj()
BankConfig *bc;
double multiplier; //for improved banks script
std::vector<ui32> artifacts; //fixed and deterministic
ui32 daycounter;
void initObj() override;
const std::string & getHoverText() const override;
void initialize() const;
void reset(ui16 var1);
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 & index & multiplier & artifacts & daycounter & bc;
}
protected:
void setPropertyDer(ui8 what, ui32 val) override;
};
class DLL_LINKAGE CGPyramid : public CBank
{
public:
ui16 spell;
void initObj() override;
const std::string & getHoverText() const override;
void newTurn() const override {}; //empty, no reset
void onHeroVisit(const CGHeroInstance * h) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CBank&>(*this);
h & spell;
}
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,227 @@
#pragma once
#include "CObjectHandler.h"
#include "CGArmedInstance.h"
#include "../CArtHandler.h" // For CArtifactSet
#include "../CRandomGenerator.h"
/*
* CObjectHandler.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
}
};

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

@ -0,0 +1,334 @@
/*
* 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 "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"
/*
* CObjectHandler.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 @@
/*
* 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 "CGPandoraBox.h"
#include "NetPacks.h"
#include "../client/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,73 @@
#pragma once
#include "CObjectHandler.h"
#include "CGArmedInstance.h"
/*
* CObjectHandler.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 "CGArmedInstance.h"
#include "../CTownHandler.h" // For CTown
/*
* CObjectHandler.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

@ -7,11 +7,11 @@
#include "GameConstants.h"
#include "StringConstants.h"
#include "CGeneralTextHandler.h"
#include "CObjectHandler.h"
#include "CModHandler.h"
#include "JsonNode.h"
#include "CRewardableConstructor.h"
#include "MapObjects.h"
/*
* CObjectClassesHandler.cpp, part of VCMI engine

View File

@ -1,10 +1,11 @@
#pragma once
#include "GameConstants.h"
#include "../lib/ConstTransitivePtr.h"
#include "IHandlerBase.h"
#include "ObjectTemplate.h"
#include "../GameConstants.h"
#include "../ConstTransitivePtr.h"
#include "../IHandlerBase.h"
/*
* CObjectClassesHandler.h, part of VCMI engine
*

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

861
lib/mapObjects/CQuest.cpp Normal file
View File

@ -0,0 +1,861 @@
/*
* 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 "CQuest.h"
#include "NetPacks.h"
#include "../client/CSoundBase.h"
#include "../CGeneralTextHandler.h"
#include "../CHeroHandler.h"
#include "CObjectClassesHandler.h"
using namespace boost::assign;
std::map <PlayerColor, std::set <ui8> > CGKeys::playerKeyMap;
///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);
}
static std::string & visitedTxt(const bool visited)
{
int id = visited ? 352 : 353;
return VLC->generaltexth->allTexts[id];
}
bool CQuest::checkQuest (const CGHeroInstance * h) const
{
switch (missionType)
{
case MISSION_NONE:
return true;
case MISSION_LEVEL:
if (m13489val <= h->level)
return true;
return false;
case MISSION_PRIMARY_STAT:
for (int i = 0; i < GameConstants::PRIMARY_SKILLS; ++i)
{
if (h->getPrimSkillLevel(static_cast<PrimarySkill::PrimarySkill>(i)) < m2stats[i])
return false;
}
return true;
case MISSION_KILL_HERO:
case MISSION_KILL_CREATURE:
if (!h->cb->getObjByQuestIdentifier(m13489val))
return true;
return false;
case MISSION_ART:
for (auto & elem : m5arts)
{
if (h->hasArt(elem))
continue;
return false; //if the artifact was not found
}
return true;
case MISSION_ARMY:
{
std::vector<CStackBasicDescriptor>::const_iterator cre;
TSlots::const_iterator it;
ui32 count;
for (cre = m6creatures.begin(); cre != m6creatures.end(); ++cre)
{
for (count = 0, it = h->Slots().begin(); it != h->Slots().end(); ++it)
{
if (it->second->type == cre->type)
count += it->second->count;
}
if (count < cre->count) //not enough creatures of this kind
return false;
}
}
return true;
case MISSION_RESOURCES:
for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, +1)) //including Mithril ?
{ //Quest has no direct access to callback
if (h->cb->getResource (h->tempOwner, i) < m7resources[i])
return false;
}
return true;
case MISSION_HERO:
if (m13489val == h->type->ID.getNum())
return true;
return false;
case MISSION_PLAYER:
if (m13489val == h->getOwner().getNum())
return true;
return false;
default:
return false;
}
}
void CQuest::getVisitText (MetaString &iwText, std::vector<Component> &components, bool isCustom, bool firstVisit, const CGHeroInstance * h) const
{
std::string text;
bool failRequirements = (h ? !checkQuest(h) : true);
if (firstVisit)
{
isCustom = isCustomFirst;
iwText << (text = firstVisitText);
}
else if (failRequirements)
{
isCustom = isCustomNext;
iwText << (text = nextVisitText);
}
switch (missionType)
{
case MISSION_LEVEL:
components.push_back(Component (Component::EXPERIENCE, 0, m13489val, 0));
if (!isCustom)
iwText.addReplacement(m13489val);
break;
case MISSION_PRIMARY_STAT:
{
MetaString loot;
for (int i = 0; i < 4; ++i)
{
if (m2stats[i])
{
components.push_back(Component (Component::PRIM_SKILL, i, m2stats[i], 0));
loot << "%d %s";
loot.addReplacement(m2stats[i]);
loot.addReplacement(VLC->generaltexth->primarySkillNames[i]);
}
}
if (!isCustom)
iwText.addReplacement(loot.buildList());
}
break;
case MISSION_KILL_HERO:
components.push_back(Component(Component::HERO_PORTRAIT, heroPortrait, 0, 0));
if (!isCustom)
addReplacements(iwText, text);
break;
case MISSION_HERO:
//FIXME: portrait may not match hero, if custom portrait was set in map editor
components.push_back(Component (Component::HERO_PORTRAIT, VLC->heroh->heroes[m13489val]->imageIndex, 0, 0));
if (!isCustom)
iwText.addReplacement(VLC->heroh->heroes[m13489val]->name);
break;
case MISSION_KILL_CREATURE:
{
components.push_back(Component(stackToKill));
if (!isCustom)
{
addReplacements(iwText, text);
}
}
break;
case MISSION_ART:
{
MetaString loot;
for (auto & elem : m5arts)
{
components.push_back(Component (Component::ARTIFACT, elem, 0, 0));
loot << "%s";
loot.addReplacement(MetaString::ART_NAMES, elem);
}
if (!isCustom)
iwText.addReplacement(loot.buildList());
}
break;
case MISSION_ARMY:
{
MetaString loot;
for (auto & elem : m6creatures)
{
components.push_back(Component(elem));
loot << "%s";
loot.addReplacement(elem);
}
if (!isCustom)
iwText.addReplacement(loot.buildList());
}
break;
case MISSION_RESOURCES:
{
MetaString loot;
for (int i = 0; i < 7; ++i)
{
if (m7resources[i])
{
components.push_back(Component (Component::RESOURCE, i, m7resources[i], 0));
loot << "%d %s";
loot.addReplacement(m7resources[i]);
loot.addReplacement(MetaString::RES_NAMES, i);
}
}
if (!isCustom)
iwText.addReplacement(loot.buildList());
}
break;
case MISSION_PLAYER:
components.push_back(Component (Component::FLAG, m13489val, 0, 0));
if (!isCustom)
iwText.addReplacement(VLC->generaltexth->colors[m13489val]);
break;
}
}
void CQuest::getRolloverText (MetaString &ms, bool onHover) const
{
if (onHover)
ms << "\n\n";
ms << VLC->generaltexth->quests[missionType-1][onHover ? 3 : 4][textOption];
switch (missionType)
{
case MISSION_LEVEL:
ms.addReplacement(m13489val);
break;
case MISSION_PRIMARY_STAT:
{
MetaString loot;
for (int i = 0; i < 4; ++i)
{
if (m2stats[i])
{
loot << "%d %s";
loot.addReplacement(m2stats[i]);
loot.addReplacement(VLC->generaltexth->primarySkillNames[i]);
}
}
ms.addReplacement(loot.buildList());
}
break;
case MISSION_KILL_HERO:
ms.addReplacement(heroName);
break;
case MISSION_KILL_CREATURE:
ms.addReplacement(stackToKill);
break;
case MISSION_ART:
{
MetaString loot;
for (auto & elem : m5arts)
{
loot << "%s";
loot.addReplacement(MetaString::ART_NAMES, elem);
}
ms.addReplacement(loot.buildList());
}
break;
case MISSION_ARMY:
{
MetaString loot;
for (auto & elem : m6creatures)
{
loot << "%s";
loot.addReplacement(elem);
}
ms.addReplacement(loot.buildList());
}
break;
case MISSION_RESOURCES:
{
MetaString loot;
for (int i = 0; i < 7; ++i)
{
if (m7resources[i])
{
loot << "%d %s";
loot.addReplacement(m7resources[i]);
loot.addReplacement(MetaString::RES_NAMES, i);
}
}
ms.addReplacement(loot.buildList());
}
break;
case MISSION_HERO:
ms.addReplacement(VLC->heroh->heroes[m13489val]->name);
break;
case MISSION_PLAYER:
ms.addReplacement(VLC->generaltexth->colors[m13489val]);
break;
default:
break;
}
}
void CQuest::getCompletionText (MetaString &iwText, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const
{
iwText << completedText;
switch (missionType)
{
case CQuest::MISSION_LEVEL:
if (!isCustomComplete)
iwText.addReplacement(m13489val);
break;
case CQuest::MISSION_PRIMARY_STAT:
if (vstd::contains (completedText,'%')) //there's one case when there's nothing to replace
{
MetaString loot;
for (int i = 0; i < 4; ++i)
{
if (m2stats[i])
{
loot << "%d %s";
loot.addReplacement(m2stats[i]);
loot.addReplacement(VLC->generaltexth->primarySkillNames[i]);
}
}
if (!isCustomComplete)
iwText.addReplacement(loot.buildList());
}
break;
case CQuest::MISSION_ART:
{
MetaString loot;
for (auto & elem : m5arts)
{
loot << "%s";
loot.addReplacement(MetaString::ART_NAMES, elem);
}
if (!isCustomComplete)
iwText.addReplacement(loot.buildList());
}
break;
case CQuest::MISSION_ARMY:
{
MetaString loot;
for (auto & elem : m6creatures)
{
loot << "%s";
loot.addReplacement(elem);
}
if (!isCustomComplete)
iwText.addReplacement(loot.buildList());
}
break;
case CQuest::MISSION_RESOURCES:
{
MetaString loot;
for (int i = 0; i < 7; ++i)
{
if (m7resources[i])
{
loot << "%d %s";
loot.addReplacement(m7resources[i]);
loot.addReplacement(MetaString::RES_NAMES, i);
}
}
if (!isCustomComplete)
iwText.addReplacement(loot.buildList());
}
break;
case MISSION_KILL_HERO:
case MISSION_KILL_CREATURE:
if (!isCustomComplete)
addReplacements(iwText, completedText);
break;
case MISSION_HERO:
if (!isCustomComplete)
iwText.addReplacement(VLC->heroh->heroes[m13489val]->name);
break;
case MISSION_PLAYER:
if (!isCustomComplete)
iwText.addReplacement(VLC->generaltexth->colors[m13489val]);
break;
}
}
void CGSeerHut::setObjToKill()
{
if (quest->missionType == CQuest::MISSION_KILL_CREATURE)
{
quest->stackToKill = getCreatureToKill(false)->getStack(SlotID(0)); //FIXME: stacks tend to disappear (desync?) on server :?
assert(quest->stackToKill.type);
quest->stackToKill.count = 0; //no count in info window
quest->stackDirection = checkDirection();
}
else if (quest->missionType == CQuest::MISSION_KILL_HERO)
{
quest->heroName = getHeroToKill(false)->name;
quest->heroPortrait = getHeroToKill(false)->portrait;
}
}
void CGSeerHut::init()
{
seerName = *RandomGeneratorUtil::nextItem(VLC->generaltexth->seerNames, cb->gameState()->getRandomGenerator());
quest->textOption = cb->gameState()->getRandomGenerator().nextInt(2);
}
void CGSeerHut::initObj()
{
init();
quest->progress = CQuest::NOT_ACTIVE;
if (quest->missionType)
{
if (!quest->isCustomFirst)
quest->firstVisitText = VLC->generaltexth->quests[quest->missionType-1][0][quest->textOption];
if (!quest->isCustomNext)
quest->nextVisitText = VLC->generaltexth->quests[quest->missionType-1][1][quest->textOption];
if (!quest->isCustomComplete)
quest->completedText = VLC->generaltexth->quests[quest->missionType-1][2][quest->textOption];
}
else
{
quest->progress = CQuest::COMPLETE;
quest->firstVisitText = VLC->generaltexth->seerEmpty[quest->textOption];
}
}
void CGSeerHut::getRolloverText (MetaString &text, bool onHover) const
{
quest->getRolloverText (text, onHover);//TODO: simplify?
if (!onHover)
text.addReplacement(seerName);
}
const std::string & CGSeerHut::getHoverText() const
{
switch (ID)
{
case Obj::SEER_HUT:
if (quest->progress != CQuest::NOT_ACTIVE)
{
hoverName = VLC->generaltexth->allTexts[347];
boost::algorithm::replace_first(hoverName,"%s", seerName);
}
else //just seer hut
hoverName = VLC->objtypeh->getObjectName(ID);
break;
case Obj::QUEST_GUARD:
hoverName = VLC->objtypeh->getObjectName(ID);
break;
default:
logGlobal->debugStream() << "unrecognized quest object";
}
if (quest->progress & quest->missionType) //rollover when the quest is active
{
MetaString ms;
getRolloverText (ms, true);
hoverName += ms.toString();
}
return hoverName;
}
void CQuest::addReplacements(MetaString &out, const std::string &base) const
{
switch(missionType)
{
case MISSION_KILL_CREATURE:
out.addReplacement(stackToKill);
if (std::count(base.begin(), base.end(), '%') == 2) //say where is placed monster
{
out.addReplacement(VLC->generaltexth->arraytxt[147+stackDirection]);
}
break;
case MISSION_KILL_HERO:
out.addReplacement(heroName);
break;
}
}
bool IQuestObject::checkQuest(const CGHeroInstance* h) const
{
return quest->checkQuest(h);
}
void IQuestObject::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const
{
quest->getVisitText (text,components, isCustom, FirstVisit, h);
}
void CGSeerHut::getCompletionText(MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h) const
{
quest->getCompletionText (text, components, isCustom, h);
switch (rewardType)
{
case EXPERIENCE: components.push_back(Component (Component::EXPERIENCE, 0, h->calculateXp(rVal), 0));
break;
case MANA_POINTS: components.push_back(Component (Component::PRIM_SKILL, 5, rVal, 0));
break;
case MORALE_BONUS: components.push_back(Component (Component::MORALE, 0, rVal, 0));
break;
case LUCK_BONUS: components.push_back(Component (Component::LUCK, 0, rVal, 0));
break;
case RESOURCES: components.push_back(Component (Component::RESOURCE, rID, rVal, 0));
break;
case PRIMARY_SKILL: components.push_back(Component (Component::PRIM_SKILL, rID, rVal, 0));
break;
case SECONDARY_SKILL: components.push_back(Component (Component::SEC_SKILL, rID, rVal, 0));
break;
case ARTIFACT: components.push_back(Component (Component::ARTIFACT, rID, 0, 0));
break;
case SPELL: components.push_back(Component (Component::SPELL, rID, 0, 0));
break;
case CREATURE: components.push_back(Component (Component::CREATURE, rID, rVal, 0));
break;
}
}
void CGSeerHut::setPropertyDer (ui8 what, ui32 val)
{
switch (what)
{
case 10:
quest->progress = static_cast<CQuest::Eprogress>(val);
break;
}
}
void CGSeerHut::newTurn() const
{
if (quest->lastDay >= 0 && quest->lastDay < cb->getDate()-1) //time is up
{
cb->setObjProperty (id, 10, CQuest::COMPLETE);
}
}
void CGSeerHut::onHeroVisit( const CGHeroInstance * h ) const
{
InfoWindow iw;
iw.player = h->getOwner();
if (quest->progress < CQuest::COMPLETE)
{
bool firstVisit = !quest->progress;
bool failRequirements = !checkQuest(h);
bool isCustom=false;
if (firstVisit)
{
isCustom = quest->isCustomFirst;
cb->setObjProperty (id, 10, CQuest::IN_PROGRESS);
AddQuest aq;
aq.quest = QuestInfo (quest, this, visitablePos());
aq.player = h->tempOwner;
cb->sendAndApply (&aq); //TODO: merge with setObjProperty?
}
else if (failRequirements)
{
isCustom = quest->isCustomNext;
}
if (firstVisit || failRequirements)
{
getVisitText (iw.text, iw.components, isCustom, firstVisit, h);
cb->showInfoDialog(&iw);
}
if (!failRequirements) // propose completion, also on first visit
{
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundBase::QUEST;
getCompletionText (bd.text, bd.components, isCustom, h);
cb->showBlockingDialog (&bd);
return;
}
}
else
{
iw.text << VLC->generaltexth->seerEmpty[quest->textOption];
if (ID == Obj::SEER_HUT)
iw.text.addReplacement(seerName);
cb->showInfoDialog(&iw);
}
}
int CGSeerHut::checkDirection() const
{
int3 cord = getCreatureToKill()->pos;
if ((double)cord.x/(double)cb->getMapSize().x < 0.34) //north
{
if ((double)cord.y/(double)cb->getMapSize().y < 0.34) //northwest
return 8;
else if ((double)cord.y/(double)cb->getMapSize().y < 0.67) //north
return 1;
else //northeast
return 2;
}
else if ((double)cord.x/(double)cb->getMapSize().x < 0.67) //horizontal
{
if ((double)cord.y/(double)cb->getMapSize().y < 0.34) //west
return 7;
else if ((double)cord.y/(double)cb->getMapSize().y < 0.67) //central
return 9;
else //east
return 3;
}
else //south
{
if ((double)cord.y/(double)cb->getMapSize().y < 0.34) //southwest
return 6;
else if ((double)cord.y/(double)cb->getMapSize().y < 0.67) //south
return 5;
else //southeast
return 4;
}
}
void CGSeerHut::finishQuest(const CGHeroInstance * h, ui32 accept) const
{
if (accept)
{
switch (quest->missionType)
{
case CQuest::MISSION_ART:
for (auto & elem : quest->m5arts)
{
cb->removeArtifact(ArtifactLocation(h, h->getArtPos(elem, false)));
}
break;
case CQuest::MISSION_ARMY:
cb->takeCreatures(h->id, quest->m6creatures);
break;
case CQuest::MISSION_RESOURCES:
for (int i = 0; i < 7; ++i)
{
cb->giveResource(h->getOwner(), static_cast<Res::ERes>(i), -quest->m7resources[i]);
}
break;
default:
break;
}
cb->setObjProperty (id, 10, CQuest::COMPLETE); //mission complete
completeQuest(h); //make sure to remove QuestGuard at the very end
}
}
void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
{
switch (rewardType)
{
case EXPERIENCE:
{
TExpType expVal = h->calculateXp(rVal);
cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false);
break;
}
case MANA_POINTS:
{
cb->setManaPoints(h->id, h->mana+rVal);
break;
}
case MORALE_BONUS: case LUCK_BONUS:
{
Bonus hb(Bonus::ONE_WEEK, (rewardType == 3 ? Bonus::MORALE : Bonus::LUCK),
Bonus::OBJECT, rVal, h->id.getNum(), "", -1);
GiveBonus gb;
gb.id = h->id.getNum();
gb.bonus = hb;
cb->giveHeroBonus(&gb);
}
break;
case RESOURCES:
cb->giveResource(h->getOwner(), static_cast<Res::ERes>(rID), rVal);
break;
case PRIMARY_SKILL:
cb->changePrimSkill(h, static_cast<PrimarySkill::PrimarySkill>(rID), rVal, false);
break;
case SECONDARY_SKILL:
cb->changeSecSkill(h, SecondarySkill(rID), rVal, false);
break;
case ARTIFACT:
cb->giveHeroNewArtifact(h, VLC->arth->artifacts[rID],ArtifactPosition::FIRST_AVAILABLE);
break;
case SPELL:
{
std::set<SpellID> spell;
spell.insert (SpellID(rID));
cb->changeSpells(h, true, spell);
}
break;
case CREATURE:
{
CCreatureSet creatures;
creatures.setCreature(SlotID(0), CreatureID(rID), rVal);
cb->giveCreatures(this, h, creatures, false);
}
break;
default:
break;
}
}
const CGHeroInstance * CGSeerHut::getHeroToKill(bool allowNull) const
{
const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->m13489val);
if(allowNull && !o)
return nullptr;
assert(o && (o->ID == Obj::HERO || o->ID == Obj::PRISON));
return static_cast<const CGHeroInstance*>(o);
}
const CGCreature * CGSeerHut::getCreatureToKill(bool allowNull) const
{
const CGObjectInstance *o = cb->getObjByQuestIdentifier(quest->m13489val);
if(allowNull && !o)
return nullptr;
assert(o && o->ID == Obj::MONSTER);
return static_cast<const CGCreature*>(o);
}
void CGSeerHut::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
finishQuest(hero, answer);
}
void CGQuestGuard::init()
{
blockVisit = true;
quest->textOption = cb->gameState()->getRandomGenerator().nextInt(3, 5);
}
void CGQuestGuard::completeQuest(const CGHeroInstance *h) const
{
cb->removeObject(this);
}
void CGKeys::setPropertyDer (ui8 what, ui32 val) //101-108 - enable key for player 1-8
{
if (what >= 101 && what <= (100 + PlayerColor::PLAYER_LIMIT_I))
{
PlayerColor player(what-101);
playerKeyMap[player].insert((ui8)val);
}
else
logGlobal->errorStream() << boost::format("Unexpected properties requested to set: what=%d, val=%d") % (int)what % val;
}
bool CGKeys::wasMyColorVisited (PlayerColor player) const
{
if (vstd::contains(playerKeyMap[player], subID)) //creates set if it's not there
return true;
else
return false;
}
const std::string& CGKeys::getHoverText() const
{
bool visited = wasMyColorVisited (cb->getLocalPlayer());
hoverName = getName() + "\n" + visitedTxt(visited);
return hoverName;
}
const std::string CGKeys::getName() const
{
std::string name;
name = VLC->generaltexth->tentColors[subID] + " " + VLC->objtypeh->getObjectName(ID);
return name;
}
bool CGKeymasterTent::wasVisited (PlayerColor player) const
{
return wasMyColorVisited (player);
}
void CGKeymasterTent::onHeroVisit( const CGHeroInstance * h ) const
{
int txt_id;
if (!wasMyColorVisited (h->getOwner()) )
{
cb->setObjProperty(id, h->tempOwner.getNum()+101, subID);
txt_id=19;
}
else
txt_id=20;
showInfoDialog(h,txt_id,soundBase::CAVEHEAD);
}
void CGBorderGuard::initObj()
{
//ui32 m13489val = subID; //store color as quest info
blockVisit = true;
}
void CGBorderGuard::getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h) const
{
text << std::pair<ui8,ui32>(11,18);
}
void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const
{
if (!onHover)
text << VLC->generaltexth->tentColors[subID] << " " << VLC->objtypeh->getObjectName(Obj::KEYMASTER);
}
bool CGBorderGuard::checkQuest (const CGHeroInstance * h) const
{
return wasMyColorVisited (h->tempOwner);
}
void CGBorderGuard::onHeroVisit( const CGHeroInstance * h ) const
{
if (wasMyColorVisited (h->getOwner()) )
{
BlockingDialog bd (true, false);
bd.player = h->getOwner();
bd.soundID = soundBase::QUEST;
bd.text.addTxt (MetaString::ADVOB_TXT, 17);
cb->showBlockingDialog (&bd);
}
else
{
showInfoDialog(h,18,soundBase::CAVEHEAD);
AddQuest aq;
aq.quest = QuestInfo (quest, this, visitablePos());
aq.player = h->tempOwner;
cb->sendAndApply (&aq);
//TODO: add this quest only once OR check for multiple instances later
}
}
void CGBorderGuard::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const
{
if (answer)
cb->removeObject(this);
}
void CGBorderGate::onHeroVisit( const CGHeroInstance * h ) const //TODO: passability
{
if (!wasMyColorVisited (h->getOwner()) )
{
showInfoDialog(h,18,0);
AddQuest aq;
aq.quest = QuestInfo (quest, this, visitablePos());
aq.player = h->tempOwner;
cb->sendAndApply (&aq);
}
}
ui8 CGBorderGate::getPassableness() const
{
ui8 ret = 0;
for (int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
ret |= wasMyColorVisited(PlayerColor(i))<<i;
return ret;
}

198
lib/mapObjects/CQuest.h Normal file
View File

@ -0,0 +1,198 @@
#pragma once
#include "CObjectHandler.h"
#include "CGArmedInstance.h"
#include "../CCreatureSet.h"
#include "../NetPacksBase.h"
/*
* CObjectHandler.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 CQuest
{
public:
enum Emission {MISSION_NONE = 0, MISSION_LEVEL = 1, MISSION_PRIMARY_STAT = 2, MISSION_KILL_HERO = 3, MISSION_KILL_CREATURE = 4,
MISSION_ART = 5, MISSION_ARMY = 6, MISSION_RESOURCES = 7, MISSION_HERO = 8, MISSION_PLAYER = 9, MISSION_KEYMASTER = 10};
enum Eprogress {NOT_ACTIVE, IN_PROGRESS, COMPLETE};
si32 qid; //unique quest id for serialization / identification
Emission missionType;
Eprogress progress;
si32 lastDay; //after this day (first day is 0) mission cannot be completed; if -1 - no limit
ui32 m13489val;
std::vector<ui32> m2stats;
std::vector<ui16> m5arts; //artifacts id
std::vector<CStackBasicDescriptor> m6creatures; //pair[cre id, cre count], CreatureSet info irrelevant
std::vector<ui32> m7resources; //TODO: use resourceset?
//following field are used only for kill creature/hero missions, the original objects became inaccessible after their removal, so we need to store info needed for messages / hover text
ui8 textOption;
CStackBasicDescriptor stackToKill;
ui8 stackDirection;
std::string heroName; //backup of hero name
si32 heroPortrait;
std::string firstVisitText, nextVisitText, completedText;
bool isCustomFirst, isCustomNext, isCustomComplete;
CQuest(){missionType = MISSION_NONE;}; //default constructor
virtual ~CQuest(){};
virtual bool checkQuest (const CGHeroInstance * h) const; //determines whether the quest is complete or not
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
virtual void getCompletionText (MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h = nullptr) const;
virtual void getRolloverText (MetaString &text, bool onHover) const; //hover or quest log entry
virtual void completeQuest (const CGHeroInstance * h) const {};
virtual void addReplacements(MetaString &out, const std::string &base) const;
bool operator== (const CQuest & quest) const
{
return (quest.qid == qid);
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & qid & missionType & progress & lastDay & m13489val & m2stats & m5arts & m6creatures & m7resources
& textOption & stackToKill & stackDirection & heroName & heroPortrait
& firstVisitText & nextVisitText & completedText & isCustomFirst & isCustomNext & isCustomComplete;
}
};
class DLL_LINKAGE IQuestObject
{
public:
CQuest * quest;
IQuestObject(): quest(new CQuest()){};
virtual ~IQuestObject() {};
virtual void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
virtual bool checkQuest (const CGHeroInstance * h) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & quest;
}
};
class DLL_LINKAGE CGSeerHut : public CArmedInstance, public IQuestObject //army is used when giving reward
{
public:
enum ERewardType {NOTHING, EXPERIENCE, MANA_POINTS, MORALE_BONUS, LUCK_BONUS, RESOURCES, PRIMARY_SKILL, SECONDARY_SKILL, ARTIFACT, SPELL, CREATURE};
ERewardType rewardType;
si32 rID; //reward ID
si32 rVal; //reward value
std::string seerName;
CGSeerHut() : IQuestObject(){};
void initObj() override;
const std::string & getHoverText() const override;
void newTurn() const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
virtual void init();
int checkDirection() const; //calculates the region of map where monster is placed
void setObjToKill(); //remember creatures / heroes to kill after they are initialized
const CGHeroInstance *getHeroToKill(bool allowNull = false) const;
const CGCreature *getCreatureToKill(bool allowNull = false) const;
void getRolloverText (MetaString &text, bool onHover) const;
void getCompletionText(MetaString &text, std::vector<Component> &components, bool isCustom, const CGHeroInstance * h = nullptr) const;
void finishQuest (const CGHeroInstance * h, ui32 accept) const; //common for both objects
virtual void completeQuest (const CGHeroInstance * h) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this) & static_cast<IQuestObject&>(*this);
h & rewardType & rID & rVal & seerName;
}
protected:
void setPropertyDer(ui8 what, ui32 val) override;
};
class DLL_LINKAGE CGQuestGuard : public CGSeerHut
{
public:
CGQuestGuard() : CGSeerHut(){};
void init() override;
void completeQuest (const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGSeerHut&>(*this);
}
};
class DLL_LINKAGE CGKeys : public CGObjectInstance //Base class for Keymaster and guards
{
public:
static std::map <PlayerColor, std::set <ui8> > playerKeyMap; //[players][keysowned]
//SubID 0 - lightblue, 1 - green, 2 - red, 3 - darkblue, 4 - brown, 5 - purple, 6 - white, 7 - black
const std::string getName() const; //depending on color
bool wasMyColorVisited (PlayerColor player) const;
const std::string & getHoverText() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
protected:
void setPropertyDer(ui8 what, ui32 val) override;
};
class DLL_LINKAGE CGKeymasterTent : public CGKeys
{
public:
bool wasVisited (PlayerColor player) const;
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CGBorderGuard : public CGKeys, public IQuestObject
{
public:
CGBorderGuard() : IQuestObject(){};
void initObj() override;
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
void getVisitText (MetaString &text, std::vector<Component> &components, bool isCustom, bool FirstVisit, const CGHeroInstance * h = nullptr) const;
void getRolloverText (MetaString &text, bool onHover) const;
bool checkQuest (const CGHeroInstance * h) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<IQuestObject&>(*this);
h & static_cast<CGObjectInstance&>(*this);
h & blockVisit;
}
};
class DLL_LINKAGE CGBorderGate : public CGBorderGuard
{
public:
CGBorderGate() : CGBorderGuard(){};
void onHeroVisit(const CGHeroInstance * h) const override;
ui8 getPassableness() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGBorderGuard&>(*this); //need to serialize or object will be empty
}
};

View File

@ -1,8 +1,9 @@
#pragma once
#include "mapObjects/CRewardableObject.h"
#include "CRewardableObject.h"
#include "CObjectClassesHandler.h"
#include "JsonNode.h"
#include "../JsonNode.h"
/*
* CObjectConstructor.h, part of VCMI engine

View File

@ -15,6 +15,8 @@
#include "../client/CSoundBase.h"
#include "NetPacks.h"
#include "CObjectClassesHandler.h"
bool CRewardLimiter::heroAllowed(const CGHeroInstance * hero) const
{
if (dayOfWeek != 0)

View File

@ -1,7 +1,9 @@
#pragma once
#include "CObjectHandler.h"
#include "NetPacksBase.h"
#include "CGArmedInstance.h"
#include "../NetPacksBase.h"
/*
* CRewardableObject.h, part of VCMI engine

View File

@ -0,0 +1,25 @@
#pragma once
/*
* MapObjects.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
*
*/
// Helper header that includes all map objects, similar to old CObjectHandler.h
// Possible TODO - remove this header after CObjectHandler.cpp will be fully split into smaller files
#include "CObjectHandler.h"
#include "CGArmedInstance.h"
#include "CGBank.h"
#include "CGHeroInstance.h"
#include "CGMarket.h"
#include "CGTownInstance.h"
#include "CGPandoraBox.h"
#include "CRewardableObject.h"
#include "MiscObjects.h"
#include "CQuest.h"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,377 @@
#pragma once
#include "CObjectHandler.h"
#include "CGArmedInstance.h"
/*
* CObjectHandler.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 CPlayersVisited: public CGObjectInstance
{
public:
std::set<PlayerColor> players; //players that visited this object
bool wasVisited(PlayerColor player) const;
bool wasVisited(TeamID team) const;
void setPropertyDer(ui8 what, ui32 val) override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & players;
}
};
class DLL_LINKAGE CGCreature : public CArmedInstance //creatures on map
{
enum Action {
FIGHT = -2, FLEE = -1, JOIN_FOR_FREE = 0 //values > 0 mean gold price
};
public:
ui32 identifier; //unique code for this monster (used in missions)
si8 character; //character of this set of creatures (0 - the most friendly, 4 - the most hostile) => on init changed to -4 (compliant) ... 10 value (savage)
std::string message; //message printed for attacking hero
TResources resources; // resources given to hero that has won with monsters
ArtifactID gainedArtifact; //ID of artifact gained to hero, -1 if none
bool neverFlees; //if true, the troops will never flee
bool notGrowingTeam; //if true, number of units won't grow
ui64 temppower; //used to handle fractional stack growth for tiny stacks
bool refusedJoining;
void onHeroVisit(const CGHeroInstance * h) const override;
const std::string & getHoverText() const override;
void initObj() override;
void newTurn() const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
struct DLL_LINKAGE formationInfo // info about merging stacks after battle back into one
{
si32 basicType;
ui32 randomFormation; //random seed used to determine number of stacks and is there's upgraded stack
template <typename Handler> void serialize(Handler &h, const int version)
{
h & basicType & randomFormation;
}
} formation;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & identifier & character & message & resources & gainedArtifact & neverFlees & notGrowingTeam & temppower;
h & refusedJoining & formation;
}
protected:
void setPropertyDer(ui8 what, ui32 val) override;
private:
void fight(const CGHeroInstance *h) const;
void flee( const CGHeroInstance * h ) const;
void fleeDecision(const CGHeroInstance *h, ui32 pursue) const;
void joinDecision(const CGHeroInstance *h, int cost, ui32 accept) const;
int takenAction(const CGHeroInstance *h, bool allowJoin=true) const; //action on confrontation: -2 - fight, -1 - flee, >=0 - will join for given value of gold (may be 0)
};
class DLL_LINKAGE CGSignBottle : public CGObjectInstance //signs and ocean bottles
{
public:
std::string message;
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & message;
}
};
class DLL_LINKAGE CGWitchHut : public CPlayersVisited
{
public:
std::vector<si32> allowedAbilities;
ui32 ability;
const std::string & getHoverText() const override;
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);
h & allowedAbilities & ability;
}
};
class DLL_LINKAGE CGScholar : public CGObjectInstance
{
public:
enum EBonusType {PRIM_SKILL, SECONDARY_SKILL, SPELL, RANDOM = 255};
EBonusType bonusType;
ui16 bonusID; //ID of skill/spell
// void giveAnyBonus(const CGHeroInstance * h) const; //TODO: remove
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & bonusType & bonusID;
}
};
class DLL_LINKAGE CGGarrison : public CArmedInstance
{
public:
bool removableUnits;
ui8 getPassableness() const;
void onHeroVisit(const CGHeroInstance * h) const override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & removableUnits;
}
};
class DLL_LINKAGE CGArtifact : public CArmedInstance
{
public:
CArtifactInstance *storedArtifact;
std::string message;
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 pick( const CGHeroInstance * h ) const;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & message & storedArtifact;
}
};
class DLL_LINKAGE CGResource : public CArmedInstance
{
public:
ui32 amount; //0 if random
std::string message;
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
void collectRes(PlayerColor player) const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & amount & message;
}
};
class DLL_LINKAGE CGShrine : public CPlayersVisited
{
public:
SpellID spell; //id of spell or NONE if random
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
const std::string & getHoverText() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);;
h & spell;
}
};
class DLL_LINKAGE CGMine : public CArmedInstance
{
public:
Res::ERes producedResource;
ui32 producedQuantity;
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 flagMine(PlayerColor player) const;
void newTurn() const override;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CArmedInstance&>(*this);
h & producedResource & producedQuantity;
}
ui32 defaultResProduction();
};
class DLL_LINKAGE CGTeleport : public CGObjectInstance //teleports and subterranean gates
{
public:
static std::map<Obj, std::map<int, std::vector<ObjectInstanceID> > > objs; //teleports: map[ID][subID] => vector of ids
static std::vector<std::pair<ObjectInstanceID, ObjectInstanceID> > gates; //subterranean gates: pairs of ids
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
static void postInit();
static ObjectInstanceID getMatchingGate(ObjectInstanceID id); //receives id of one subterranean gate and returns id of the paired one, -1 if none
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CGMagicWell : public CGObjectInstance //objects giving bonuses to luck/morale/movement
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
const std::string & getHoverText() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CGSirens : public CGObjectInstance
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
const std::string & getHoverText() const override;
void initObj() override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CGObservatory : public CGObjectInstance //Redwood observatory
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CGBoat : public CGObjectInstance
{
public:
ui8 direction;
const CGHeroInstance *hero; //hero on board
void initObj() override;
CGBoat()
{
hero = nullptr;
direction = 4;
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this) & direction & hero;
}
};
class CGShipyard : public CGObjectInstance, public IShipyard
{
public:
void getOutOffsets(std::vector<int3> &offsets) const; //offsets to obj pos when we boat can be placed
CGShipyard();
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
h & static_cast<IShipyard&>(*this);
}
};
class DLL_LINKAGE CGMagi : public CGObjectInstance
{
public:
static std::map <si32, std::vector<ObjectInstanceID> > eyelist; //[subID][id], supports multiple sets as in H5
void initObj() override;
void onHeroVisit(const CGHeroInstance * h) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
};
class DLL_LINKAGE CCartographer : public CPlayersVisited
{
///behaviour varies depending on surface and floor
public:
void onHeroVisit(const CGHeroInstance * h) const override;
void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);
}
};
class DLL_LINKAGE CGDenOfthieves : public CGObjectInstance
{
void onHeroVisit(const CGHeroInstance * h) const override;
};
class DLL_LINKAGE CGObelisk : public CPlayersVisited
{
public:
static ui8 obeliskCount; //how many obelisks are on map
static std::map<TeamID, ui8> visited; //map: team_id => how many obelisks has been visited
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
const std::string & getHoverText() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CPlayersVisited&>(*this);
}
protected:
void setPropertyDer(ui8 what, ui32 val) override;
};
class DLL_LINKAGE CGLighthouse : public CGObjectInstance
{
public:
void onHeroVisit(const CGHeroInstance * h) const override;
void initObj() override;
const std::string & getHoverText() const override;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<CGObjectInstance&>(*this);
}
void giveBonusTo( PlayerColor player ) const;
};

View File

@ -10,7 +10,7 @@
#include "../CGeneralTextHandler.h"
#include "../StartInfo.h"
#include "../CArtHandler.h" //for hero crossover
#include "../mapObjects/CObjectHandler.h" //for hero crossover
#include "../mapObjects/CGHeroInstance.h"//for hero crossover
#include "../CHeroHandler.h"
#include "CMapService.h"
#include "CMap.h"

View File

@ -7,6 +7,7 @@
#include "../CTownHandler.h"
#include "../CHeroHandler.h"
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../CGeneralTextHandler.h"
#include "../CSpellHandler.h"
#include "CMapEditManager.h"

View File

@ -12,7 +12,9 @@
#pragma once
#include "../ConstTransitivePtr.h"
#include "../mapObjects/CObjectHandler.h"
#include "../mapObjects/MiscObjects.h" // To serialize static props
#include "../mapObjects/CQuest.h" // To serialize static props
#include "../mapObjects/CGTownInstance.h" // To serialize static props
#include "../ResourceSet.h"
#include "../int3.h"
#include "../GameConstants.h"

View File

@ -4,6 +4,7 @@
#include "../JsonNode.h"
#include "../filesystem/Filesystem.h"
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/CGHeroInstance.h"
#include "../VCMI_Lib.h"
MapRect::MapRect() : x(0), y(0), z(0), width(0), height(0)

View File

@ -20,9 +20,8 @@
#include "../CCreatureHandler.h"
#include "../CGeneralTextHandler.h"
#include "../CHeroHandler.h"
#include "../mapObjects/CObjectHandler.h"
#include "../mapObjects/CRewardableObject.h"
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/MapObjects.h"
#include "../VCMI_Lib.h"
#include "../NetPacksBase.h"

View File

@ -14,7 +14,8 @@
#include "CMapService.h"
#include "../GameConstants.h"
#include "../ResourceSet.h"
#include "../mapObjects/CObjectClassesHandler.h"
//#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/ObjectTemplate.h"
#include "../int3.h"

View File

@ -4,14 +4,13 @@
#include "../NetPacks.h"
#include "../VCMI_Lib.h"
#include "../CArtHandler.h"
#include "../mapObjects/CObjectHandler.h"
#include "../mapObjects/CRewardableObject.h"
#include "../CGameState.h"
#include "../CHeroHandler.h"
#include "../CTownHandler.h"
#include "../CModHandler.h" //needed?
#include "../mapObjects/CObjectClassesHandler.h"
#include "../mapObjects/CRewardableConstructor.h"
#include "../mapObjects/MapObjects.h"
/*
* RegisterTypes.h, part of VCMI engine

View File

@ -5,8 +5,8 @@
#include "../VCMI_Lib.h"
#include "../CGeneralTextHandler.h"
#include "../mapping/CMapEditManager.h"
#include "../mapObjects/CObjectHandler.h"
#include "../mapObjects/CObjectClassesHandler.h"
//#include "../mapObjects/CObjectHandler.h"
//#include "../mapObjects/CObjectClassesHandler.h"
#include "../CTownHandler.h"
#include "../StringConstants.h"
#include "../filesystem/Filesystem.h"

View File

@ -15,7 +15,6 @@
#include "../CRandomGenerator.h"
#include "CMapGenOptions.h"
#include "CRmgTemplateZone.h"
#include "../mapObjects/CObjectHandler.h"
#include "../int3.h"
class CMap;

View File

@ -18,6 +18,8 @@
#include "../CTownHandler.h"
#include "../CCreatureHandler.h"
#include "../mapObjects/CObjectClassesHandler.h"
class CMap;
class CMapEditManager;

View File

@ -8,9 +8,9 @@
#include "../lib/CModHandler.h"
#include "../lib/CArtHandler.h"
#include "../lib/CBuildingHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/CSpellHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h"

View File

@ -8,7 +8,7 @@
#include "../lib/Connection.h"
#include "../lib/CModHandler.h"
#include "../lib/CArtHandler.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
//#include "../lib/mapObjects/CObjectClassesHandler.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CHeroHandler.h"
#include "../lib/CTownHandler.h"
@ -26,7 +26,7 @@
#include "../lib/VCMIDirs.h"
#include "CGameHandler.h"
#include "../lib/mapping/CMapInfo.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/GameConstants.h"
#include "../lib/logging/CBasicLogConfigurator.h"
#include "../lib/CConfigHandler.h"

View File

@ -2,7 +2,7 @@
#include "../lib/NetPacks.h"
#include "CGameHandler.h"
#include "../lib/mapObjects/CObjectHandler.h"
//#include "../lib/mapObjects/CObjectHandler.h"
#include "../lib/IGameCallback.h"
#include "../lib/mapping/CMap.h"
#include "../lib/CGameState.h"