mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Merged changes from upstream and fixed compilation caused by API changes
This commit is contained in:
commit
32b6568b65
3
.gitignore
vendored
3
.gitignore
vendored
@ -5,3 +5,6 @@
|
||||
*.a
|
||||
*.res
|
||||
*.layout
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
/CMakeLists.txt.user
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "../../lib/VCMI_Lib.h"
|
||||
|
||||
using boost::optional;
|
||||
shared_ptr<CBattleCallback> cbc;
|
||||
static shared_ptr<CBattleCallback> cbc;
|
||||
|
||||
#define LOGL(text) print(text)
|
||||
#define LOGFL(text, formattingEl) print(boost::str(boost::format(text) % formattingEl))
|
||||
@ -28,8 +28,12 @@ struct Priorities
|
||||
range::copy(VLC->objh->resVals, std::back_inserter(resourceTypeBaseValues));
|
||||
stackEvaluator = [](const CStack*){ return 1.0; };
|
||||
}
|
||||
} priorities;
|
||||
};
|
||||
|
||||
Priorities *priorities = nullptr;
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = nullptr)
|
||||
{
|
||||
@ -52,6 +56,8 @@ bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityIn
|
||||
return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename Container, typename Pred>
|
||||
auto sum(const Container & c, Pred p) -> decltype(p(*std::begin(c)))
|
||||
{
|
||||
@ -453,9 +459,9 @@ void CBattleAI::attemptCastingSpell()
|
||||
int damageDealt = 0, damageReceived = 0;
|
||||
|
||||
auto stacksSuffering = cb->getAffectedCreatures(ps.spell, skillLevel, playerID, ps.dest);
|
||||
vstd::erase_if(stacksSuffering, [&](const CStack *stack) -> bool
|
||||
vstd::erase_if(stacksSuffering, [&](const CStack * s) -> bool
|
||||
{
|
||||
return cb->battleIsImmune(hero, ps.spell, ECastingMode::HERO_CASTING, ps.dest);
|
||||
return ESpellCastProblem::OK != cb->battleStackIsImmune(hero, ps.spell, ECastingMode::HERO_CASTING, s);
|
||||
});
|
||||
|
||||
if(stacksSuffering.empty())
|
||||
@ -624,8 +630,10 @@ const TBonusListPtr StackWithBonuses::getAllBonuses(const CSelector &selector, c
|
||||
|
||||
int AttackPossibility::damageDiff() const
|
||||
{
|
||||
const auto dealtDmgValue = priorities.stackEvaluator(enemy) * damageDealt;
|
||||
const auto receivedDmgValue = priorities.stackEvaluator(attack.attacker) * damageReceived;
|
||||
if (!priorities)
|
||||
priorities = new Priorities;
|
||||
const auto dealtDmgValue = priorities->stackEvaluator(enemy) * damageDealt;
|
||||
const auto receivedDmgValue = priorities->stackEvaluator(attack.attacker) * damageReceived;
|
||||
return dealtDmgValue - receivedDmgValue;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
<OutDir>..</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
@ -93,6 +93,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -115,6 +116,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
@ -7,7 +7,13 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
const char *g_cszAiName = "Battle AI";
|
||||
#ifdef __ANDROID__
|
||||
#define GetGlobalAiVersion BattleAI_GetGlobalAiVersion
|
||||
#define GetAiName BattleAI_GetAiName
|
||||
#define GetNewBattleAI BattleAI_GetNewBattleAI
|
||||
#endif
|
||||
|
||||
static const char *g_cszAiName = "Battle AI";
|
||||
|
||||
extern "C" DLL_EXPORT int GetGlobalAiVersion()
|
||||
{
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "StdInc.h"
|
||||
#include "CEmptyAI.h"
|
||||
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
void CEmptyAI::init(shared_ptr<CCallback> CB)
|
||||
{
|
||||
cb = CB;
|
||||
@ -15,12 +17,12 @@ void CEmptyAI::yourTurn()
|
||||
|
||||
void CEmptyAI::heroGotLevel(const CGHeroInstance *hero, PrimarySkill::PrimarySkill pskill, std::vector<SecondarySkill> &skills, QueryID queryID)
|
||||
{
|
||||
cb->selectionMade(rand() % skills.size(), queryID);
|
||||
cb->selectionMade(CRandomGenerator::getDefault().nextInt(skills.size() - 1), queryID);
|
||||
}
|
||||
|
||||
void CEmptyAI::commanderGotLevel(const CCommanderInstance * commander, std::vector<ui32> skills, QueryID queryID)
|
||||
{
|
||||
cb->selectionMade(rand() % skills.size(), queryID);
|
||||
cb->selectionMade(CRandomGenerator::getDefault().nextInt(skills.size() - 1), queryID);
|
||||
}
|
||||
|
||||
void CEmptyAI::showBlockingDialog(const std::string &text, const std::vector<Component> &components, QueryID askID, const int soundID, bool selection, bool cancel)
|
||||
|
@ -96,7 +96,7 @@
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
<OutDir>..</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
@ -115,6 +115,7 @@
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)EmptyAI.dll</OutputFile>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -150,6 +151,7 @@
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)EmptyAI.dll</OutputFile>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
@ -123,7 +123,7 @@
|
||||
<IntDir>$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
<OutDir>..</OutDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
|
||||
shared_ptr<CBattleCallback> cbc;
|
||||
static shared_ptr<CBattleCallback> cbc;
|
||||
|
||||
CStupidAI::CStupidAI(void)
|
||||
: side(-1)
|
||||
@ -60,6 +60,8 @@ bool isMoreProfitable(const EnemyInfo &ei1, const EnemyInfo& ei2)
|
||||
return (ei1.adi-ei1.adr) < (ei2.adi - ei2.adr);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
int distToNearestNeighbour(BattleHex hex, const ReachabilityInfo::TDistances& dists, BattleHex *chosenHex = nullptr)
|
||||
{
|
||||
int ret = 1000000;
|
||||
@ -81,6 +83,8 @@ bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityIn
|
||||
return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2)
|
||||
{
|
||||
int shooters[2] = {0}; //count of shooters on hexes
|
||||
@ -104,8 +108,9 @@ BattleAction CStupidAI::activeStack( const CStack * stack )
|
||||
if(stack->type->idNumber == CreatureID::CATAPULT)
|
||||
{
|
||||
BattleAction attack;
|
||||
static const int wallHexes[] = {50, 183, 182, 130, 62, 29, 12, 95};
|
||||
attack.destinationTile = wallHexes[ rand()%ARRAY_COUNT(wallHexes) ];
|
||||
static const std::vector<int> wallHexes = boost::assign::list_of(50)(183)(182)(130)(62)(29)(12)(95);
|
||||
|
||||
attack.destinationTile = *RandomGeneratorUtil::nextItem(wallHexes, CRandomGenerator::getDefault());
|
||||
attack.actionType = Battle::CATAPULT;
|
||||
attack.additionalInfo = 0;
|
||||
attack.side = side;
|
||||
@ -327,4 +332,3 @@ void CStupidAI::loadGame(CISer<CLoadFile> &h, const int version)
|
||||
//TODO to be implemented with saving/loading during the battles
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
<OutDir>..</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
@ -94,6 +94,7 @@
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalOptions>-Zm150 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -114,6 +115,7 @@
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
@ -7,7 +7,13 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
const char *g_cszAiName = "Stupid AI 0.1";
|
||||
#ifdef __ANDROID__
|
||||
#define GetGlobalAiVersion StupidAI_GetGlobalAiVersion
|
||||
#define GetAiName StupidAI_GetAiName
|
||||
#define GetNewBattleAI StupidAI_GetNewBattleAI
|
||||
#endif
|
||||
|
||||
static const char *g_cszAiName = "Stupid AI 0.1";
|
||||
|
||||
extern "C" DLL_EXPORT int GetGlobalAiVersion()
|
||||
{
|
||||
|
@ -344,11 +344,12 @@ bool isReachable(const CGObjectInstance *obj)
|
||||
return cb->getPathInfo(obj->visitablePos())->turns < 255;
|
||||
}
|
||||
|
||||
bool canBeEmbarkmentPoint(const TerrainTile *t)
|
||||
bool canBeEmbarkmentPoint(const TerrainTile *t, bool fromWater)
|
||||
{
|
||||
//tile must be free of with unoccupied boat
|
||||
return !t->blocked
|
||||
|| (t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::BOAT);
|
||||
|| (!fromWater && t->visitableObjects.size() == 1 && t->topVisitableId() == Obj::BOAT);
|
||||
//do not try to board when in water sector
|
||||
}
|
||||
|
||||
int3 whereToExplore(HeroPtr h)
|
||||
|
@ -183,7 +183,7 @@ int howManyTilesWillBeDiscovered(const int3 &pos, int radious, CCallback * cbp);
|
||||
int howManyTilesWillBeDiscovered(int radious, int3 pos, crint3 dir);
|
||||
void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out);
|
||||
|
||||
bool canBeEmbarkmentPoint(const TerrainTile *t);
|
||||
bool canBeEmbarkmentPoint(const TerrainTile *t, bool fromWater);
|
||||
bool isBlockedBorderGate(int3 tileToHit);
|
||||
bool isReachable(const CGObjectInstance *obj);
|
||||
bool isCloser(const CGObjectInstance *lhs, const CGObjectInstance *rhs);
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/CHeroHandler.h"
|
||||
|
||||
|
||||
/*
|
||||
* CCreatureHandler.h, part of VCMI engine
|
||||
*
|
||||
@ -1143,7 +1144,8 @@ void VCAI::buildStructure(const CGTownInstance * t)
|
||||
//Possible - allow "locking" on specific building (build prerequisites and then building itself)
|
||||
|
||||
TResources currentRes = cb->getResourceAmount();
|
||||
int townIncome = t->dailyIncome();
|
||||
TResources currentIncome = t->dailyIncome();
|
||||
int townIncome = currentIncome[Res::GOLD];
|
||||
|
||||
if (tryBuildAnyStructure(t, std::vector<BuildingID>(essential, essential + ARRAY_COUNT(essential))))
|
||||
return;
|
||||
@ -1212,7 +1214,6 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
|
||||
std::vector<const CGObjectInstance *> possibleDestinations;
|
||||
for(const CGObjectInstance *obj : visitableObjs)
|
||||
{
|
||||
const int3 pos = obj->visitablePos();
|
||||
if (isGoodForVisit(obj, h))
|
||||
{
|
||||
possibleDestinations.push_back(obj);
|
||||
@ -1304,7 +1305,7 @@ void VCAI::wander(HeroPtr h)
|
||||
if(townsReachable.size())
|
||||
{
|
||||
boost::sort(townsReachable, compareReinforcements);
|
||||
dests.emplace_back(townsReachable.back());
|
||||
dests.push_back(townsReachable.back());
|
||||
}
|
||||
else if(townsNotReachable.size())
|
||||
{
|
||||
@ -1680,12 +1681,13 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
}
|
||||
ret = !i;
|
||||
}
|
||||
if (h)
|
||||
{
|
||||
if (auto visitedObject = frontOrNull(cb->getVisitableObjs(h->visitablePos()))) //we stand on something interesting
|
||||
{
|
||||
if (visitedObject != *h)
|
||||
performObjectInteraction (visitedObject, h);
|
||||
//BNLOG("Hero %s moved from %s to %s at %s", h->name % startHpos % visitedObject->hoverName % h->visitablePos());
|
||||
//throw goalFulfilledException (CGoal(GET_OBJ).setobjid(visitedObject->id));
|
||||
}
|
||||
}
|
||||
if(h) //we could have lost hero after last move
|
||||
{
|
||||
@ -1703,8 +1705,8 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
|
||||
erase_if_present (lockedHeroes, h); //hero seemingly is confused
|
||||
throw cannotFulfillGoalException("Invalid path found!"); //FIXME: should never happen
|
||||
}
|
||||
}
|
||||
logAi->debugStream() << boost::format("Hero %s moved from %s to %s. Returning %d.") % h->name % startHpos % h->visitablePos() % ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
void VCAI::tryRealize(Goals::Explore & g)
|
||||
@ -2344,22 +2346,10 @@ TResources VCAI::estimateIncome() const
|
||||
TResources ret;
|
||||
for(const CGTownInstance *t : cb->getTownsInfo())
|
||||
{
|
||||
ret[Res::GOLD] += t->dailyIncome();
|
||||
ret += t->dailyIncome();
|
||||
}
|
||||
|
||||
|
||||
//TODO duplikuje newturn
|
||||
if(t->hasBuilt(BuildingID::RESOURCE_SILO)) //there is resource silo
|
||||
{
|
||||
if(t->town->primaryRes == Res::WOOD_AND_ORE) //we'll give wood and ore
|
||||
{
|
||||
ret[Res::WOOD] ++;
|
||||
ret[Res::ORE] ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret[t->town->primaryRes] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(const CGObjectInstance *obj : getFlaggedObjects())
|
||||
{
|
||||
@ -2736,7 +2726,7 @@ void SectorMap::exploreNewSector(crint3 pos, int num, CCallback * cbp)
|
||||
//parent[neighPos] = curPos;
|
||||
}
|
||||
const TerrainTile *nt = cbp->getTile(neighPos, false);
|
||||
if(nt && nt->isWater() != s.water && canBeEmbarkmentPoint(nt))
|
||||
if(nt && nt->isWater() != s.water && canBeEmbarkmentPoint(nt, s.water))
|
||||
{
|
||||
s.embarkmentPoints.push_back(neighPos);
|
||||
}
|
||||
@ -2856,9 +2846,9 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case Obj::MONOLITH1:
|
||||
case Obj::MONOLITH2:
|
||||
case Obj::MONOLITH3:
|
||||
case Obj::MONOLITH_ONE_WAY_ENTRANCE:
|
||||
case Obj::MONOLITH_ONE_WAY_EXIT:
|
||||
case Obj::MONOLITH_TWO_WAY:
|
||||
case Obj::WHIRLPOOL:
|
||||
//TODO: mechanism for handling monoliths
|
||||
return false;
|
||||
@ -2884,7 +2874,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
|
||||
case Obj::MAGIC_WELL:
|
||||
return h->mana < h->manaLimit();
|
||||
case Obj::PRISON:
|
||||
return ai->myCb->getHeroesInfo().size() < GameConstants::MAX_HEROES_PER_PLAYER;
|
||||
return ai->myCb->getHeroesInfo().size() < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER;// GameConstants::MAX_HEROES_PER_PLAYER;
|
||||
|
||||
case Obj::BOAT:
|
||||
return false;
|
||||
|
@ -21,9 +21,6 @@
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../../lib/CondSh.h"
|
||||
|
||||
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),
|
||||
int3(1,1,0),int3(-1,1,0),int3(1,-1,0),int3(-1,-1,0) };
|
||||
|
||||
struct QuestInfo;
|
||||
|
||||
/*
|
||||
|
@ -80,7 +80,7 @@
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
<OutDir>..</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
<OutDir>$(VCMI_Out)\AI\</OutDir>
|
||||
@ -91,11 +91,11 @@
|
||||
</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
|
||||
<AdditionalOptions>/Zm195 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalOptions>/Zm210 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;FuzzyLite.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(VCMI_Out);$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -117,11 +117,11 @@
|
||||
</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
|
||||
<AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalOptions>/Zm199 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;FuzzyLite.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>$(VCMI_Out);$(OutDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories>..\..\..\libs;..\..;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
@ -5,7 +5,13 @@
|
||||
#define strcpy_s(a, b, c) strncpy(a, c, b)
|
||||
#endif
|
||||
|
||||
const char *g_cszAiName = "VCAI";
|
||||
#ifdef __ANDROID__
|
||||
#define GetGlobalAiVersion VCAI_GetGlobalAiVersion
|
||||
#define GetAiName VCAI_GetAiName
|
||||
#define GetNewAI VCAI_GetNewAI
|
||||
#endif
|
||||
|
||||
static const char *g_cszAiName = "VCAI";
|
||||
|
||||
extern "C" DLL_EXPORT int GetGlobalAiVersion()
|
||||
{
|
||||
|
5
AUTHORS
5
AUTHORS
@ -1,4 +1,4 @@
|
||||
VCMI PROJECT CODE CONTRIBUTORS:
|
||||
VCMI PROJECT CODE CONTRIBUTORS:
|
||||
|
||||
Michał Urbańczyk aka Tow, <impono@gmail.com>
|
||||
* project originator; programming, making releases, website
|
||||
@ -46,5 +46,8 @@ Ivan Savenko, <saven.ivan@gmail.com>
|
||||
Benjamin Gentner aka beegee, <>
|
||||
* battle support, programming
|
||||
|
||||
Alexey aka Macron1Robot, <>
|
||||
* minor modding changes
|
||||
|
||||
Alexander Shishkin aka alexvins,
|
||||
* MinGW platform support, modding related programming
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "lib/IGameCallback.h"
|
||||
#include "lib/CGameInfoCallback.h"
|
||||
#include "lib/int3.h" // for int3
|
||||
|
||||
/*
|
||||
* CCallback.h, part of VCMI engine
|
||||
@ -29,6 +30,7 @@ struct CPathsInfo;
|
||||
struct CPack;
|
||||
class IBattleEventsReceiver;
|
||||
class IGameEventsReceiver;
|
||||
struct ArtifactLocation;
|
||||
|
||||
class IBattleCallback
|
||||
{
|
||||
|
@ -5,8 +5,10 @@ GENERAL:
|
||||
ADVENTURE AI:
|
||||
|
||||
ADVENTURE MAP:
|
||||
* Heroes auto-level primary and secondary skill levels according to experience
|
||||
|
||||
BATTLES:
|
||||
* Wall hit/miss sound will be played when using catapult during siege
|
||||
|
||||
SPELLS:
|
||||
* New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format
|
||||
@ -14,7 +16,11 @@ SPELLS:
|
||||
MODS:
|
||||
* Support for submods - mod may have their own "submods" located in <modname>/Mods directory
|
||||
* Mods may provide their own changelogs and screenshots that will be visible in Launcher
|
||||
* Mods cas now add new (offensive, buffs, debuffs) spells and change existing
|
||||
* Mods can now add new (offensive, buffs, debuffs) spells and change existing
|
||||
* Mods can use custom mage guild background pictures and videos for taverns, setting of resources daily income for buildings
|
||||
|
||||
GENERAL:
|
||||
* Added configuring of heroes quantity per player allowed in game
|
||||
|
||||
0.94 -> 0.95 (Mar 01 2014)
|
||||
GENERAL:
|
||||
|
25
Global.h
25
Global.h
@ -24,12 +24,12 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
#if !defined(__clang__) && defined(__GNUC__) && (GCC_VERSION < 460)
|
||||
# error VCMI requires at least gcc-4.6 for successful compilation or clang-3.1. Please update your compiler
|
||||
#if !defined(__clang__) && defined(__GNUC__) && (GCC_VERSION < 470)
|
||||
# error VCMI requires at least gcc-4.7.2 for successful compilation or clang-3.1. Please update your compiler
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && (GCC_VERSION == 470 || GCC_VERSION == 471)
|
||||
# error This GCC version has buggy std::array::at version and should not be used. Please update to 4.7.2 or use 4.6.x.
|
||||
# error This GCC version has buggy std::array::at version and should not be used. Please update to 4.7.2 or later
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
@ -42,11 +42,6 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
# define CPP11_USE_INITIALIZERS_LIST
|
||||
#endif
|
||||
|
||||
//override keyword - not present in gcc-4.6
|
||||
#if !defined(_MSC_VER) && !defined(__clang__) && !(defined(__GNUC__) && (GCC_VERSION >= 470))
|
||||
# define override
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
/* Suppress some compiler warnings */
|
||||
/* ---------------------------------------------------------------------------- */
|
||||
@ -114,7 +109,6 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
|
||||
#include <boost/range/algorithm.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <boost/math/special_functions/round.hpp>
|
||||
|
||||
|
||||
@ -553,19 +547,6 @@ namespace vstd
|
||||
});
|
||||
}
|
||||
|
||||
static inline int retreiveRandNum(const std::function<int()> &randGen)
|
||||
{
|
||||
if (randGen)
|
||||
return randGen();
|
||||
else
|
||||
return rand();
|
||||
}
|
||||
|
||||
template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const std::function<int()> &randGen)
|
||||
{
|
||||
return v.at(retreiveRandNum(randGen) % v.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void advance(T &obj, int change)
|
||||
{
|
||||
|
@ -22,11 +22,6 @@
|
||||
"config/wog/heroClasses.json"
|
||||
],
|
||||
|
||||
"spells" :
|
||||
[
|
||||
"config/wog/spells.json"
|
||||
],
|
||||
|
||||
"filesystem":
|
||||
{
|
||||
"" :
|
||||
|
34
README
34
README
@ -1,22 +1,20 @@
|
||||
VCMI Project
|
||||
Copyright (C) 2007-2014 VCMI Team (check AUTHORS file for the contributors list)
|
||||
# VCMI Project
|
||||
VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities. To use VCMI you need to own original data files.
|
||||
|
||||
VCMI is an open-source project aiming to reimplement HMM3:WoG game engine,
|
||||
giving it new and extended possibilities.
|
||||
Wiki: http://wiki.vcmi.eu
|
||||
Forums: http://forum.vcmi.eu
|
||||
Bugtracker: http://bugs.vcmi.eu/
|
||||
## Links
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 (included in the license.txt)
|
||||
of the License, or (at your option) any later version.
|
||||
* Homepage: http://vcmi.eu/
|
||||
* Wiki: http://wiki.vcmi.eu/
|
||||
* Forums: http://forum.vcmi.eu/
|
||||
* Bugtracker: http://bugs.vcmi.eu/
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
## Installation
|
||||
For installation of latest release see release announcement on http://vcmi.eu/
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
For building from source see project wiki at http://wiki.vcmi.eu/
|
||||
|
||||
## Copyright and license
|
||||
|
||||
VCMI Project is released under GPL version 2 or later
|
||||
|
||||
Copyright (C) 2007-2014 VCMI Team (check AUTHORS file for the contributors list)
|
||||
|
@ -57,102 +57,100 @@ Global
|
||||
RD|x64 = RD|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.Debug|Win32.Build.0 = RD|Win32
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.Debug|x64.Build.0 = Debug|x64
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.RD|Win32.Build.0 = RD|Win32
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.RD|x64.ActiveCfg = RD|x64
|
||||
{8355EBA8-65C2-44A4-BC2D-78053E1BF2D6}.RD|x64.Build.0 = RD|x64
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.Debug|Win32.Build.0 = RD|Win32
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.Debug|x64.Build.0 = Debug|x64
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.RD|Win32.Build.0 = RD|Win32
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.RD|x64.ActiveCfg = RD|x64
|
||||
{B952FFC5-3039-4DE1-9F08-90ACDA483D8F}.RD|x64.Build.0 = RD|x64
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.Debug|Win32.Build.0 = RD|Win32
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.Debug|x64.Build.0 = Debug|x64
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|Win32.Build.0 = RD|Win32
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|x64.ActiveCfg = RD|x64
|
||||
{8AF697C3-465E-4910-B31B-576A9ECDB309}.RD|x64.Build.0 = RD|x64
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|Win32.Build.0 = RD|Win32
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.Debug|x64.Build.0 = Debug|x64
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.RD|Win32.Build.0 = RD|Win32
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.RD|x64.ActiveCfg = RD|x64
|
||||
{15DABC90-234A-4B6B-9EEB-777C4768B82B}.RD|x64.Build.0 = RD|x64
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|Win32.Build.0 = RD|Win32
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.Debug|x64.Build.0 = Debug|x64
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|Win32.Build.0 = RD|Win32
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|x64.ActiveCfg = RD|x64
|
||||
{8F202F43-106D-4F63-AD9D-B1D43E803E8C}.RD|x64.Build.0 = RD|x64
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|Win32.Build.0 = RD|Win32
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.Debug|x64.Build.0 = Debug|x64
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|Win32.Build.0 = RD|Win32
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|x64.ActiveCfg = RD|x64
|
||||
{276C3DB0-7A6B-4417-8E5C-322B08633AAC}.RD|x64.Build.0 = RD|x64
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.Debug|Win32.Build.0 = RD|Win32
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.Debug|x64.Build.0 = Debug|x64
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|Win32.Build.0 = RD|Win32
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|x64.ActiveCfg = RD|x64
|
||||
{D15B34EC-A32C-4968-9B0B-66998B579364}.RD|x64.Build.0 = RD|x64
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|Win32.Build.0 = RD|Win32
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.Debug|x64.Build.0 = Debug|x64
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|Win32.Build.0 = RD|Win32
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|x64.ActiveCfg = RD|x64
|
||||
{C0300513-E845-43B4-9A4F-E8817EAEF57C}.RD|x64.Build.0 = RD|x64
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|Win32.ActiveCfg = Release|Win32
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.RD|Win32.ActiveCfg = Release|Win32
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.RD|Win32.Build.0 = Release|Win32
|
||||
{B12702AD-ABFB-343A-A199-8E24837244A3}.RD|x64.ActiveCfg = Release|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|Win32.Build.0 = RD|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.Debug|x64.Build.0 = Debug|x64
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|Win32.Build.0 = RD|Win32
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|x64.ActiveCfg = RD|x64
|
||||
{C41C4EB6-6F74-4F37-9FB0-9FA6BF377837}.RD|x64.Build.0 = RD|x64
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.Debug|Win32.Build.0 = RD|Win32
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.Debug|x64.Build.0 = Debug|x64
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.RD|Win32.Build.0 = RD|Win32
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.RD|x64.ActiveCfg = RD|x64
|
||||
{BA25F3F0-EB87-4164-AAB9-073C50A3557A}.RD|x64.Build.0 = RD|x64
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.Debug|Win32.Build.0 = RD|Win32
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.Debug|x64.Build.0 = Debug|x64
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.RD|Win32.Build.0 = RD|Win32
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.RD|x64.ActiveCfg = RD|x64
|
||||
{AA3CC588-9D08-4178-A1E8-C71561E99723}.RD|x64.Build.0 = RD|x64
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.Debug|Win32.ActiveCfg = RD|Win32
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.Debug|Win32.Build.0 = RD|Win32
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.RD|Win32.ActiveCfg = RD|Win32
|
||||
{5B6946C8-A24F-4223-8415-5E16A238ACED}.RD|Win32.Build.0 = RD|Win32
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/filesystem/ISimpleResourceLoader.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
#include "CBitmapHandler.h"
|
||||
#include "Graphics.h"
|
||||
@ -1432,7 +1433,7 @@ void CCreatureAnim::loopPreview(bool warMachine)
|
||||
if (anim.size(elem))
|
||||
available.push_back(elem);
|
||||
|
||||
size_t rnd = rand()%(available.size()*2);
|
||||
size_t rnd = CRandomGenerator::getDefault().nextInt(available.size() * 2 - 1);
|
||||
|
||||
if (rnd >= available.size())
|
||||
{
|
||||
|
@ -358,7 +358,7 @@ void CHeroGSlot::clickLeft(tribool down, bool previousState)
|
||||
bool allow = true;
|
||||
if(upg) //moving hero out of town - check if it is allowed
|
||||
{
|
||||
if(!hero && LOCPLINT->cb->howManyHeroes(false) >= 8)
|
||||
if(!hero && LOCPLINT->cb->howManyHeroes(false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
|
||||
{
|
||||
std::string tmp = CGI->generaltexth->allTexts[18]; //You already have %d adventuring heroes under your command.
|
||||
boost::algorithm::replace_first(tmp,"%d",boost::lexical_cast<std::string>(LOCPLINT->cb->howManyHeroes(false)));
|
||||
@ -847,7 +847,9 @@ void CCastleBuildings::enterTownHall()
|
||||
|
||||
void CCastleBuildings::openMagesGuild()
|
||||
{
|
||||
GH.pushInt(new CMageGuildScreen(LOCPLINT->castleInt));
|
||||
std::string mageGuildBackground;
|
||||
mageGuildBackground = LOCPLINT->castleInt->town->town->clientInfo.guildBackground;
|
||||
GH.pushInt(new CMageGuildScreen(LOCPLINT->castleInt,mageGuildBackground));
|
||||
}
|
||||
|
||||
void CCastleBuildings::openTownHall()
|
||||
@ -964,7 +966,8 @@ void CCastleInterface::recreateIcons()
|
||||
size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
|
||||
|
||||
icon->setFrame(iconIndex);
|
||||
income->setText(boost::lexical_cast<std::string>(town->dailyIncome()));
|
||||
TResources townIncome = town->dailyIncome();
|
||||
income->setText(boost::lexical_cast<std::string>(townIncome[Res::GOLD]));
|
||||
|
||||
hall = new CTownInfo( 80, 413, town, true);
|
||||
fort = new CTownInfo(122, 413, town, false);
|
||||
@ -1636,9 +1639,12 @@ void CFortScreen::RecruitArea::clickRight(tribool down, bool previousState)
|
||||
clickLeft(down, false); //r-click does same as l-click - opens recr. window
|
||||
}
|
||||
|
||||
CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner):
|
||||
CWindowObject(BORDERED, "TPMAGE")
|
||||
|
||||
|
||||
|
||||
CMageGuildScreen::CMageGuildScreen(CCastleInterface * owner,std::string imagem) :CWindowObject(BORDERED,imagem)
|
||||
{
|
||||
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL;
|
||||
|
||||
window = new CPicture(owner->town->town->clientInfo.guildWindow , 332, 76);
|
||||
|
@ -360,7 +360,7 @@ class CMageGuildScreen : public CWindowObject
|
||||
CGStatusBar *statusBar;
|
||||
|
||||
public:
|
||||
CMageGuildScreen(CCastleInterface * owner);
|
||||
CMageGuildScreen(CCastleInterface * owner,std::string image);
|
||||
};
|
||||
|
||||
/// The blacksmith window where you can buy available in town war machine
|
||||
|
@ -361,17 +361,18 @@ std::string InfoBoxHeroData::getHoverText()
|
||||
|
||||
std::string InfoBoxHeroData::getValueText()
|
||||
{
|
||||
if (hero)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case HERO_MANA:
|
||||
if (hero)
|
||||
return boost::lexical_cast<std::string>(hero->mana) + '/' +
|
||||
boost::lexical_cast<std::string>(hero->manaLimit());
|
||||
case HERO_EXPERIENCE:
|
||||
return boost::lexical_cast<std::string>(hero->exp);
|
||||
default:
|
||||
return InfoBoxAbstractHeroData::getValueText();
|
||||
}
|
||||
}
|
||||
return InfoBoxAbstractHeroData::getValueText();
|
||||
}
|
||||
|
||||
bool InfoBoxHeroData::prepareMessage(std::string &text, CComponent**comp)
|
||||
@ -580,7 +581,7 @@ void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstan
|
||||
std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
|
||||
for(auto & town : towns)
|
||||
{
|
||||
totalIncome += town->dailyIncome();
|
||||
totalIncome += town->dailyIncome()[Res::GOLD];
|
||||
}
|
||||
for (int i=0; i<7; i++)
|
||||
{
|
||||
|
@ -284,6 +284,10 @@ int main(int argc, char** argv)
|
||||
logGlobal->infoStream() << "Creating console and configuring logger: " << pomtime.getDiff();
|
||||
logGlobal->infoStream() << "The log file will be saved to " << logPath;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// boost will crash without this
|
||||
setenv("LANG", "C", 1);
|
||||
#endif
|
||||
// Init filesystem and settings
|
||||
preinitDLL(::console);
|
||||
settings.init();
|
||||
@ -361,8 +365,13 @@ int main(int argc, char** argv)
|
||||
|
||||
|
||||
|
||||
#ifndef __ANDROID__
|
||||
//we can properly play intro only in the main thread, so we have to move loading to the separate thread
|
||||
boost::thread loading(init);
|
||||
#else
|
||||
// on Android threaded init is broken
|
||||
init();
|
||||
#endif
|
||||
|
||||
if(!gNoGUI )
|
||||
{
|
||||
@ -372,7 +381,9 @@ int main(int argc, char** argv)
|
||||
}
|
||||
|
||||
CSDL_Ext::update(screen);
|
||||
#ifndef __ANDROID__
|
||||
loading.join();
|
||||
#endif
|
||||
logGlobal->infoStream()<<"Initialization of VCMI (together): "<<total.getDiff();
|
||||
|
||||
if(!vm.count("battle"))
|
||||
|
@ -1,3 +1,13 @@
|
||||
/*
|
||||
* CMessage.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 "CMessage.h"
|
||||
|
||||
@ -13,17 +23,6 @@
|
||||
#include "CBitmapHandler.h"
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
|
||||
/*
|
||||
* CMessage.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
|
||||
*
|
||||
*/
|
||||
|
||||
const int COMPONENT_TO_SUBTITLE = 17;
|
||||
const int BETWEEN_COMPS_ROWS = 10;
|
||||
const int BEFORE_COMPONENTS = 30;
|
||||
const int BETWEEN_COMPS = 30;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/filesystem/Filesystem.h"
|
||||
#include "../lib/StringConstants.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* CMusicHandler.cpp, part of VCMI engine
|
||||
@ -230,7 +231,7 @@ int CSoundHandler::playSound(std::string sound, int repeats)
|
||||
// Helper. Randomly select a sound from an array and play it
|
||||
int CSoundHandler::playSoundFromSet(std::vector<soundBase::soundID> &sound_vec)
|
||||
{
|
||||
return playSound(sound_vec[rand() % sound_vec.size()]);
|
||||
return playSound(*RandomGeneratorUtil::nextItem(sound_vec, CRandomGenerator::getDefault()));
|
||||
}
|
||||
|
||||
void CSoundHandler::stopSound( int handler )
|
||||
@ -504,10 +505,7 @@ bool MusicEntry::play()
|
||||
if (!setName.empty())
|
||||
{
|
||||
auto set = owner->musicsSet[setName];
|
||||
size_t entryID = rand() % set.size();
|
||||
auto iterator = set.begin();
|
||||
std::advance(iterator, entryID);
|
||||
load(iterator->second);
|
||||
load(RandomGeneratorUtil::nextItem(set, CRandomGenerator::getDefault())->second);
|
||||
}
|
||||
|
||||
logGlobal->traceStream()<<"Playing music file "<<currentName;
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "gui/CIntObjectClasses.h"
|
||||
#include "../lib/mapping/CMapService.h"
|
||||
#include "../lib/mapping/CMap.h"
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* CPreGame.cpp, part of VCMI engine
|
||||
@ -607,7 +608,7 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
|
||||
bordered = true;
|
||||
//load random background
|
||||
const JsonVector & bgNames = CGPreGameConfig::get().getConfig()["game-select"].Vector();
|
||||
bg = new CPicture(bgNames[rand() % bgNames.size()].String(), 0, 0);
|
||||
bg = new CPicture(RandomGeneratorUtil::nextItem(bgNames, CRandomGenerator::getDefault())->String(), 0, 0);
|
||||
pos = bg->center();
|
||||
}
|
||||
|
||||
@ -4136,7 +4137,7 @@ std::string CLoadingScreen::getBackground()
|
||||
}
|
||||
else
|
||||
{
|
||||
return conf[ rand() % conf.size() ].String();
|
||||
return RandomGeneratorUtil::nextItem(conf, CRandomGenerator::getDefault())->String();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -744,23 +744,26 @@ void CSpellWindow::SpellArea::clickLeft(tribool down, bool previousState)
|
||||
|
||||
if (h->getSpellSchoolLevel(CGI->spellh->objects[spell]) < 2) //not advanced or expert - teleport to nearest available city
|
||||
{
|
||||
int nearest = -1; //nearest town's ID
|
||||
double dist = -1;
|
||||
for (int g=0; g<Towns.size(); ++g)
|
||||
auto nearest = Towns.cbegin(); //nearest town's iterator
|
||||
si32 dist = LOCPLINT->cb->getTown((*nearest)->id)->pos.dist2dSQ(h->pos);
|
||||
|
||||
for (auto i = nearest + 1; i != Towns.cend(); ++i)
|
||||
{
|
||||
const CGTownInstance * dest = LOCPLINT->cb->getTown(Towns[g]->id);
|
||||
double curDist = dest->pos.dist2d(h->pos);
|
||||
if (nearest == -1 || curDist < dist)
|
||||
const CGTownInstance * dest = LOCPLINT->cb->getTown((*i)->id);
|
||||
si32 curDist = dest->pos.dist2dSQ(h->pos);
|
||||
|
||||
if (curDist < dist)
|
||||
{
|
||||
nearest = g;
|
||||
nearest = i;
|
||||
dist = curDist;
|
||||
}
|
||||
}
|
||||
if ( Towns[nearest]->visitingHero )
|
||||
|
||||
if ((*nearest)->visitingHero)
|
||||
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[123]);
|
||||
else
|
||||
{
|
||||
const CGTownInstance * town = LOCPLINT->cb->getTown(Towns[nearest]->id);
|
||||
const CGTownInstance * town = LOCPLINT->cb->getTown((*nearest)->id);
|
||||
LOCPLINT->cb->castSpell(h, spell, town->visitablePos());// - town->getVisitableOffset());
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ bool CBIKHandler::open(std::string name)
|
||||
logGlobal->errorStream() << "BIK handler: failed to open " << name;
|
||||
goto checkErrorAndClean;
|
||||
}
|
||||
//GCC wants scope of waveout to dont cross labels/swith/goto
|
||||
//GCC wants scope of waveout to don`t cross labels/swith/goto
|
||||
{
|
||||
void *waveout = GetProcAddress(dll,"_BinkOpenWaveOut@4");
|
||||
if(waveout)
|
||||
|
@ -19,7 +19,9 @@
|
||||
#include "../lib/CBuildingHandler.h"
|
||||
#include "../lib/CSpellHandler.h"
|
||||
#include "../lib/Connection.h"
|
||||
#ifndef __ANDROID__
|
||||
#include "../lib/Interprocess.h"
|
||||
#endif
|
||||
#include "../lib/NetPacks.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../lib/VCMIDirs.h"
|
||||
@ -37,7 +39,9 @@
|
||||
#include "CMT.h"
|
||||
|
||||
extern std::string NAME;
|
||||
#ifndef __ANDROID__
|
||||
namespace intpr = boost::interprocess;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Client.cpp, part of VCMI engine
|
||||
@ -809,19 +813,25 @@ void CServerHandler::waitForServer()
|
||||
startServer();
|
||||
|
||||
th.update();
|
||||
#ifndef __ANDROID__
|
||||
intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
|
||||
while(!shared->sr->ready)
|
||||
{
|
||||
shared->sr->cond.wait(slock);
|
||||
}
|
||||
#endif
|
||||
if(verbose)
|
||||
logNetwork->infoStream() << "Waiting for server: " << th.getDiff();
|
||||
}
|
||||
|
||||
CConnection * CServerHandler::connectToServer()
|
||||
{
|
||||
#ifndef __ANDROID__
|
||||
if(!shared->sr->ready)
|
||||
waitForServer();
|
||||
#else
|
||||
waitForServer();
|
||||
#endif
|
||||
|
||||
th.update(); //put breakpoint here to attach to server before it does something stupid
|
||||
CConnection *ret = justConnectToServer(settings["server"]["server"].String(), port);
|
||||
@ -839,11 +849,13 @@ CServerHandler::CServerHandler(bool runServer /*= false*/)
|
||||
port = boost::lexical_cast<std::string>(settings["server"]["port"].Float());
|
||||
verbose = true;
|
||||
|
||||
#ifndef __ANDROID__
|
||||
boost::interprocess::shared_memory_object::remove("vcmi_memory"); //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
|
||||
try
|
||||
{
|
||||
shared = new SharedMem();
|
||||
} HANDLE_EXCEPTIONC(logNetwork->errorStream() << "Cannot open interprocess memory: ";)
|
||||
#endif
|
||||
}
|
||||
|
||||
CServerHandler::~CServerHandler()
|
||||
|
@ -3726,10 +3726,16 @@ CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj):
|
||||
recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[0]; //Cannot afford a Hero
|
||||
recruit->block(true);
|
||||
}
|
||||
else if(LOCPLINT->cb->howManyHeroes(false) >= 8)
|
||||
else if(LOCPLINT->castleInt && LOCPLINT->cb->howManyHeroes(true) >= VLC->modh->settings.MAX_HEROES_AVAILABLE_PER_PLAYER)
|
||||
{
|
||||
recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[1]; //Cannot recruit. You already have %d Heroes.
|
||||
boost::algorithm::replace_first(recruit->hoverTexts[0],"%d",boost::lexical_cast<std::string>(LOCPLINT->cb->howManyHeroes()));
|
||||
boost::algorithm::replace_first(recruit->hoverTexts[0],"%d",boost::lexical_cast<std::string>(LOCPLINT->cb->howManyHeroes(true)));
|
||||
recruit->block(true);
|
||||
}
|
||||
else if((!LOCPLINT->castleInt) && LOCPLINT->cb->howManyHeroes(false) >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
|
||||
{
|
||||
recruit->hoverTexts[0] = CGI->generaltexth->tavernInfo[1]; //Cannot recruit. You already have %d Heroes.
|
||||
boost::algorithm::replace_first(recruit->hoverTexts[0], "%d", boost::lexical_cast<std::string>(LOCPLINT->cb->howManyHeroes(false)));
|
||||
recruit->block(true);
|
||||
}
|
||||
else if(LOCPLINT->castleInt && LOCPLINT->castleInt->town->visitingHero)
|
||||
@ -3742,7 +3748,9 @@ CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj):
|
||||
if(selected == -1)
|
||||
recruit->block(true);
|
||||
}
|
||||
|
||||
if (LOCPLINT->castleInt)
|
||||
CCS->videoh->open(LOCPLINT->castleInt->town->town->clientInfo.tavernVideo);
|
||||
else
|
||||
CCS->videoh->open("TAVERN.BIK");
|
||||
}
|
||||
|
||||
@ -3931,6 +3939,7 @@ void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
|
||||
{
|
||||
captureAllKeys = false;
|
||||
endEnteringText(true);
|
||||
CCS->soundh->playSound("CHAT");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -5753,7 +5762,7 @@ void CHillFortWindow::showAll (SDL_Surface *to)
|
||||
|
||||
std::string CHillFortWindow::getTextForSlot(SlotID slot)
|
||||
{
|
||||
if ( !hero->getCreature(slot) )//we dont have creature here
|
||||
if ( !hero->getCreature(slot) )//we don`t have creature here
|
||||
return "";
|
||||
|
||||
std::string str = CGI->generaltexth->allTexts[318];
|
||||
|
@ -332,7 +332,6 @@ void RemoveObject::applyFirstCl( CClient *cl )
|
||||
|
||||
CGI->mh->hideObject(o);
|
||||
|
||||
int3 pos = o->visitablePos();
|
||||
//notify interfaces about removal
|
||||
for(auto i=cl->playerint.begin(); i!=cl->playerint.end(); i++)
|
||||
{
|
||||
|
@ -71,11 +71,11 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(VCMI_Out)</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(VCMI_Out)</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\</IntDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">$(VCMI_Out)</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">..</OutDir>
|
||||
<OutDir Condition="'$(Configuration)|$(Platform)'=='RD|x64'">$(VCMI_Out)</OutDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">$(Configuration)\</IntDir>
|
||||
<IntDir Condition="'$(Configuration)|$(Platform)'=='RD|x64'">$(Configuration)\</IntDir>
|
||||
@ -107,6 +107,7 @@
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<OptimizeReferences>false</OptimizeReferences>
|
||||
<Profile>true</Profile>
|
||||
<AdditionalLibraryDirectories>..\..\libs;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<Manifest>
|
||||
<AdditionalManifestFiles>$(ProjectDir)DPIaware.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>
|
||||
@ -144,6 +145,7 @@
|
||||
<LinkTimeCodeGeneration>
|
||||
</LinkTimeCodeGeneration>
|
||||
<ShowProgress>NotSet</ShowProgress>
|
||||
<AdditionalLibraryDirectories>..\..\libs;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'">
|
||||
|
@ -834,6 +834,19 @@ void CShootingAnimation::nextFrame()
|
||||
|
||||
void CShootingAnimation::endAnim()
|
||||
{
|
||||
// play wall hit/miss sound for catapult attack
|
||||
if(!attackedStack)
|
||||
{
|
||||
if(catapultDamage > 0)
|
||||
{
|
||||
CCS->soundh->playSound("WALLHIT");
|
||||
}
|
||||
else
|
||||
{
|
||||
CCS->soundh->playSound("WALLMISS");
|
||||
}
|
||||
}
|
||||
|
||||
CAttackAnimation::endAnim();
|
||||
delete this;
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "../CVideoHandler.h"
|
||||
#include "../../lib/CTownHandler.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
#include "../../lib/CRandomGenerator.h"
|
||||
|
||||
#include "CBattleAnimations.h"
|
||||
#include "CBattleInterfaceClasses.h"
|
||||
@ -59,7 +60,7 @@ static void onAnimationFinished(const CStack *stack, CCreatureAnimation * anim)
|
||||
|
||||
if (anim->framesInGroup(CCreatureAnim::MOUSEON) > 0)
|
||||
{
|
||||
if (float(rand() % 100) < creature->animation.timeBetweenFidgets * 10)
|
||||
if (CRandomGenerator::getDefault().nextDouble(99.0) < creature->animation.timeBetweenFidgets * 10)
|
||||
anim->playOnce(CCreatureAnim::MOUSEON);
|
||||
else
|
||||
anim->setType(CCreatureAnim::HOLDING);
|
||||
@ -194,7 +195,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
logGlobal->errorStream() << bfieldType << " battlefield type does not have any backgrounds!";
|
||||
else
|
||||
{
|
||||
const std::string bgName = vstd::pickRandomElementOf(graphics->battleBacks[bfieldType], rand);
|
||||
const std::string bgName = *RandomGeneratorUtil::nextItem(graphics->battleBacks[bfieldType], CRandomGenerator::getDefault());
|
||||
background = BitmapHandler::loadBitmap(bgName, false);
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ protected:
|
||||
public:
|
||||
EAlignment alignment;
|
||||
EFonts font;
|
||||
SDL_Color color; // default font color. Can be overriden by placing "{}" into the string
|
||||
SDL_Color color; // default font color. Can be overridden by placing "{}" into the string
|
||||
};
|
||||
|
||||
/// Label which shows text
|
||||
|
@ -1,3 +1,13 @@
|
||||
/*
|
||||
* mapHandler.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 "mapHandler.h"
|
||||
|
||||
@ -17,19 +27,7 @@
|
||||
#include "../lib/GameConstants.h"
|
||||
#include "../lib/CStopWatch.h"
|
||||
#include "CMT.h"
|
||||
|
||||
/*
|
||||
* mapHandler.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
|
||||
*
|
||||
*/
|
||||
|
||||
const bool MARK_BLOCKED_POSITIONS = false;
|
||||
const bool MARK_VISITABLE_POSITIONS = false;
|
||||
#include "../lib/CRandomGenerator.h"
|
||||
|
||||
#define ADVOPT (conf.go()->ac)
|
||||
|
||||
@ -129,7 +127,7 @@ void CMapHandler::prepareFOWDefs()
|
||||
elem[j].resize(sizes.z);
|
||||
for(int k = 0; k < sizes.z; ++k)
|
||||
{
|
||||
elem[j][k] = rand()%graphics->FoWfullHide->ourImages.size();
|
||||
elem[j][k] = CRandomGenerator::getDefault().nextInt(graphics->FoWfullHide->ourImages.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,6 +197,8 @@ void CMapHandler::borderAndTerrainBitmapInit()
|
||||
{
|
||||
int terBitmapNum = -1;
|
||||
|
||||
auto & rand = CRandomGenerator::getDefault();
|
||||
|
||||
if(i==-1 && j==-1)
|
||||
terBitmapNum = 16;
|
||||
else if(i==-1 && j==(sizes.y))
|
||||
@ -208,15 +208,15 @@ void CMapHandler::borderAndTerrainBitmapInit()
|
||||
else if(i==(sizes.x) && j==(sizes.y))
|
||||
terBitmapNum = 18;
|
||||
else if(j == -1 && i > -1 && i < sizes.y)
|
||||
terBitmapNum = 22+rand()%2;
|
||||
terBitmapNum = rand.nextInt(22, 23);
|
||||
else if(i == -1 && j > -1 && j < sizes.y)
|
||||
terBitmapNum = 33+rand()%2;
|
||||
terBitmapNum = rand.nextInt(33, 34);
|
||||
else if(j == sizes.y && i >-1 && i < sizes.x)
|
||||
terBitmapNum = 29+rand()%2;
|
||||
terBitmapNum = rand.nextInt(29, 30);
|
||||
else if(i == sizes.x && j > -1 && j < sizes.y)
|
||||
terBitmapNum = 25+rand()%2;
|
||||
terBitmapNum = rand.nextInt(25, 26);
|
||||
else
|
||||
terBitmapNum = rand()%16;
|
||||
terBitmapNum = rand.nextInt(15);
|
||||
|
||||
if(terBitmapNum != -1)
|
||||
{
|
||||
@ -1083,7 +1083,7 @@ ui8 CMapHandler::getPhaseShift(const CGObjectInstance *object) const
|
||||
auto i = animationPhase.find(object);
|
||||
if(i == animationPhase.end())
|
||||
{
|
||||
ui8 ret = rand() % 255;
|
||||
ui8 ret = CRandomGenerator::getDefault().nextInt(254);
|
||||
animationPhase[object] = ret;
|
||||
return ret;
|
||||
}
|
||||
|
@ -102,9 +102,6 @@ public:
|
||||
|
||||
mutable std::map<const CGObjectInstance*, ui8> animationPhase;
|
||||
|
||||
static const bool MARK_BLOCKED_POSITIONS;
|
||||
static const bool MARK_VISITABLE_POSITIONS;
|
||||
|
||||
CMapHandler(); //c-tor
|
||||
~CMapHandler(); //d-tor
|
||||
|
||||
|
@ -59,7 +59,7 @@
|
||||
{ "id": 26, "defnames": [ "C13SPA0.DEF" ] },
|
||||
{ "id": 27, "defnames": [ "C13SPE0.DEF" ] },
|
||||
{ "id": 28, "defnames": [ "C13SPW0.DEF" ] },
|
||||
{ "id": 29, "defnames": [ "C04SPE0.DEF" ] },
|
||||
{ "id": 29, "defnames": [ "C14SPA0.DEF" ] },
|
||||
{ "id": 30, "defnames": [ "C14SPE0.DEF" ] },
|
||||
{ "id": 31, "defnames": [ "C15SPA0.DEF" ] },
|
||||
{ "id": 32, "defnames": [ "C15SPE0.DEF", "C15SPE1.DEF", "C15SPE2.DEF" ] },
|
||||
|
@ -338,7 +338,8 @@
|
||||
"resurrects" :
|
||||
{
|
||||
"type" : "SPELLCASTER",
|
||||
"subtype" : "spell.resurrection"
|
||||
"subtype" : "spell.resurrection",
|
||||
"val" : 3
|
||||
},
|
||||
"spellpoints" :
|
||||
{
|
||||
|
@ -81,6 +81,11 @@
|
||||
{
|
||||
"type" : "SPELL_IMMUNITY",
|
||||
"subtype" : "spell.chainLightning"
|
||||
},
|
||||
"armageddonImmunity" :
|
||||
{
|
||||
"type" : "SPELL_IMMUNITY",
|
||||
"subtype" : "spell.armageddon"
|
||||
}
|
||||
},
|
||||
"upgrades": ["magmaElemental"],
|
||||
@ -395,6 +400,21 @@
|
||||
"type" : "SPELLCASTER",
|
||||
"subtype" : "spell.protectEarth",
|
||||
"val" : 2
|
||||
},
|
||||
"lightingImmunity" :
|
||||
{
|
||||
"type" : "SPELL_IMMUNITY",
|
||||
"subtype" : "spell.lightningBolt"
|
||||
},
|
||||
"chainLightingImmunity" :
|
||||
{
|
||||
"type" : "SPELL_IMMUNITY",
|
||||
"subtype" : "spell.chainLightning"
|
||||
},
|
||||
"armageddonImmunity" :
|
||||
{
|
||||
"type" : "SPELL_IMMUNITY",
|
||||
"subtype" : "spell.armageddon"
|
||||
}
|
||||
},
|
||||
"graphics" :
|
||||
@ -440,6 +460,23 @@
|
||||
"type" : "SPELLCASTER",
|
||||
"subtype" : "spell.protectAir",
|
||||
"val" : 2
|
||||
},
|
||||
"meteorShowerImmunity" :
|
||||
{
|
||||
"type" : "SPELL_IMMUNITY",
|
||||
"subtype" : "spell.meteorShower"
|
||||
},
|
||||
"lightingVulnerablity" :
|
||||
{
|
||||
"type" : "MORE_DAMAGE_FROM_SPELL",
|
||||
"subtype" : "spell.lightningBolt",
|
||||
"val" : 100
|
||||
},
|
||||
"chainLightingVulnerablity" :
|
||||
{
|
||||
"type" : "MORE_DAMAGE_FROM_SPELL",
|
||||
"subtype" : "spell.chainLightning",
|
||||
"val" : 100
|
||||
}
|
||||
},
|
||||
"graphics" :
|
||||
|
@ -21,7 +21,10 @@
|
||||
"MAX_BUILDING_PER_TURN" : 1,
|
||||
"DWELLINGS_ACCUMULATE_CREATURES" : true,
|
||||
"ALL_CREATURES_GET_DOUBLE_MONTHS" : false,
|
||||
"NEGATIVE_LUCK" : false
|
||||
"NEGATIVE_LUCK" : false,
|
||||
"MAX_HEROES_AVAILABLE_PER_PLAYER" : 16,
|
||||
"MAX_HEROES_ON_MAP_PER_PLAYER" : 8
|
||||
|
||||
},
|
||||
"modules":
|
||||
{
|
||||
|
@ -116,7 +116,8 @@
|
||||
|
||||
"musicTheme" : "music/CstleTown",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBCSBACK.bmp",
|
||||
"guildWindow": "TPMAGECS.bmp",
|
||||
"buildingsIcons": "HALLCSTL.DEF",
|
||||
@ -143,7 +144,7 @@
|
||||
"mageGuild" : 4,
|
||||
"warMachine" : "ballista",
|
||||
"moatDamage" : 70,
|
||||
|
||||
"primaryResource": "ore",
|
||||
"buildings" :
|
||||
{
|
||||
"mageGuild1": { "id" : 0 },
|
||||
@ -155,12 +156,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "ore": 1, "wood": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17, "requires" : [ "shipyard" ] },
|
||||
@ -169,7 +170,7 @@
|
||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||
"special2": { "id" : 21, "requires" : [ "dwellingLvl4" ] },
|
||||
"special3": { "id" : 22, "upgrades" : "tavern" },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||
|
@ -120,7 +120,8 @@
|
||||
|
||||
"musicTheme" : "music/ElemTown",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBELBACK.bmp",
|
||||
"guildWindow": "TPMAGEEL.bmp",
|
||||
"buildingsIcons": "HALLELEM.DEF",
|
||||
@ -161,12 +162,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "mercury": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17, "requires" : [ "marketplace" ] },
|
||||
@ -174,7 +175,7 @@
|
||||
"horde1Upgr": { "id" : 19, "upgrades" : "dwellingUpLvl1", "requires" : [ "horde1" ], "mode" : "auto" },
|
||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||
"special2": { "id" : 21, "requires" : [ "mageGuild1" ] },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
||||
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||
|
@ -115,7 +115,8 @@
|
||||
|
||||
"musicTheme" : "music/Dungeon",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBDNBACK.bmp",
|
||||
"guildWindow": "TPMAGEDN.bmp",
|
||||
"buildingsIcons": "HALLDUNG.DEF",
|
||||
@ -155,10 +156,10 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"blacksmith": { "id" : 16 },
|
||||
@ -169,7 +170,7 @@
|
||||
"special2": { "id" : 21, "requires" : [ "mageGuild1" ] },
|
||||
"special3": { "id" : 22 },
|
||||
"special4": { "id" : 23 },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||
|
@ -116,7 +116,8 @@
|
||||
|
||||
"musicTheme" : "music/FortressTown",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBFRBACK.bmp",
|
||||
"guildWindow": "TPMAGEFR.bmp",
|
||||
"buildingsIcons": "HALLFORT.DEF",
|
||||
@ -143,7 +144,7 @@
|
||||
"mageGuild" : 3,
|
||||
"warMachine" : "firstAidTent",
|
||||
"moatDamage" : 90,
|
||||
|
||||
"primaryResource":"ore",
|
||||
"buildings" :
|
||||
{
|
||||
"mageGuild1": { "id" : 0 },
|
||||
@ -154,12 +155,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "wood": 1, "ore": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17, "requires" : [ "allOf", [ "townHall" ], [ "special2" ] ] },
|
||||
@ -168,7 +169,7 @@
|
||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||
"special2": { "id" : 21, "requires" : [ "fort" ] },
|
||||
"special3": { "id" : 22, "requires" : [ "special2" ] },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
|
@ -116,7 +116,8 @@
|
||||
|
||||
"musicTheme" : "music/InfernoTown",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBINBACK.bmp",
|
||||
"guildWindow": "TPMAGEIN.bmp",
|
||||
"buildingsIcons": "HALLINFR.DEF",
|
||||
@ -156,12 +157,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "mercury": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"horde1": { "id" : 18, "upgrades" : "dwellingLvl1" },
|
||||
@ -171,7 +172,7 @@
|
||||
"special4": { "id" : 23, "requires" : [ "mageGuild1" ] },
|
||||
"horde2": { "id" : 24, "upgrades" : "dwellingLvl3" },
|
||||
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl3", "requires" : [ "horde2" ], "mode" : "auto" },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||
|
@ -120,7 +120,8 @@
|
||||
|
||||
"musicTheme" : "music/NecroTown",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBNCBACK.bmp",
|
||||
"guildWindow": "TPMAGENC.bmp",
|
||||
"buildingsIcons": "HALLNECR.DEF",
|
||||
@ -147,6 +148,7 @@
|
||||
"mageGuild" : 5,
|
||||
"warMachine" : "firstAidTent",
|
||||
"moatDamage" : 70,
|
||||
"primaryResource": "ore",
|
||||
|
||||
"buildings" :
|
||||
{
|
||||
@ -160,12 +162,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "ore": 1, "wood": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17, "requires" : [ "fort" ] },
|
||||
@ -174,7 +176,7 @@
|
||||
"ship": { "id" : 20, "upgrades" : "shipyard" },
|
||||
"special2": { "id" : 21, "requires" : [ "mageGuild1" ] },
|
||||
"special3": { "id" : 22, "requires" : [ "dwellingLvl1" ] },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
||||
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||
|
@ -120,7 +120,8 @@
|
||||
|
||||
"musicTheme" : "music/Rampart",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBRMBACK.bmp",
|
||||
"guildWindow": "TPMAGERM.bmp",
|
||||
"buildingsIcons": "HALLRAMP.DEF",
|
||||
@ -160,12 +161,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "crystal": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17 },
|
||||
@ -175,7 +176,7 @@
|
||||
"special3": { "id" : 22, "requires" : [ "horde1" ] },
|
||||
"horde2": { "id" : 24, "upgrades" : "dwellingLvl5" },
|
||||
"horde2Upgr": { "id" : 25, "upgrades" : "dwellingUpLvl5", "requires" : [ "horde2" ], "mode" : "auto" },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
"extraTownHall": { "id" : 27, "requires" : [ "townHall" ], "mode" : "auto" },
|
||||
"extraCityHall": { "id" : 28, "requires" : [ "cityHall" ], "mode" : "auto" },
|
||||
"extraCapitol": { "id" : 29, "requires" : [ "capitol" ], "mode" : "auto" },
|
||||
|
@ -114,7 +114,9 @@
|
||||
|
||||
"musicTheme" : "music/Stronghold",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"primaryResource": "ore",
|
||||
"townBackground": "TBSTBACK.bmp",
|
||||
"guildWindow": "TPMAGEST.bmp",
|
||||
"buildingsIcons": "HALLSTRN.DEF",
|
||||
@ -151,12 +153,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce": { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce": { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce": { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce": { "ore": 1, "wood": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17, "requires" : [ "fort" ] },
|
||||
@ -165,7 +167,7 @@
|
||||
"special2": { "id" : 21, "requires" : [ "marketplace" ] },
|
||||
"special3": { "id" : 22, "requires" : [ "blacksmith" ] },
|
||||
"special4": { "id" : 23, "requires" : [ "fort" ] },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce": { "gold": 5000 }},
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||
|
@ -115,7 +115,8 @@
|
||||
|
||||
"musicTheme" : "music/TowerTown",
|
||||
"defaultTavern" : 5,
|
||||
|
||||
"tavernVideo" : "TAVERN.BIK",
|
||||
"guildBackground" : "TPMAGE.bmp",
|
||||
"townBackground": "TBTWBACK.bmp",
|
||||
"guildWindow": "TPMAGETW.bmp",
|
||||
"buildingsIcons": "HALLTOWR.DEF",
|
||||
@ -155,12 +156,12 @@
|
||||
"fort": { "id" : 7 },
|
||||
"citadel": { "id" : 8, "upgrades" : "fort" },
|
||||
"castle": { "id" : 9, "upgrades" : "citadel" },
|
||||
"villageHall": { "id" : 10, "mode" : "auto" },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ] },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ] },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ] },
|
||||
"villageHall": { "id" : 10, "mode" : "auto", "produce" : { "gold": 500 } },
|
||||
"townHall": { "id" : 11, "upgrades" : "villageHall", "requires" : [ "tavern" ], "produce" : { "gold": 1000 } },
|
||||
"cityHall": { "id" : 12, "upgrades" : "townHall", "requires" : [ "allOf", [ "mageGuild1" ], [ "marketplace" ], [ "blacksmith" ] ], "produce": { "gold": 2000 } },
|
||||
"capitol": { "id" : 13, "upgrades" : "cityHall", "requires" : [ "castle" ], "produce" : { "gold": 4000 } },
|
||||
"marketplace": { "id" : 14 },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ] },
|
||||
"resourceSilo": { "id" : 15, "requires" : [ "marketplace" ], "produce" : { "gems": 1 } },
|
||||
"blacksmith": { "id" : 16 },
|
||||
|
||||
"special1": { "id" : 17, "requires" : [ "marketplace" ] },
|
||||
@ -169,7 +170,7 @@
|
||||
"special2": { "id" : 21, "requires" : [ "fort" ] },
|
||||
"special3": { "id" : 22, "requires" : [ "mageGuild1" ] },
|
||||
"special4": { "id" : 23, "requires" : [ "mageGuild1" ] },
|
||||
"grail": { "id" : 26, "mode" : "grail"},
|
||||
"grail": { "id" : 26, "mode" : "grail", "produce" : { "gold": 5000 } },
|
||||
|
||||
"dwellingLvl1": { "id" : 30, "requires" : [ "fort" ] },
|
||||
"dwellingLvl2": { "id" : 31, "requires" : [ "dwellingLvl1" ] },
|
||||
|
@ -69,6 +69,10 @@
|
||||
],
|
||||
"spells" :
|
||||
[
|
||||
"config/spell_info.json"
|
||||
"config/spells/adventure.json",
|
||||
"config/spells/offensive.json",
|
||||
"config/spells/other.json",
|
||||
"config/spells/timed.json",
|
||||
"config/spells/ability.json"
|
||||
]
|
||||
}
|
||||
|
@ -239,7 +239,7 @@
|
||||
],
|
||||
"specialties":
|
||||
[
|
||||
{ "type":2, "val": 5, "subtype": 11, "info": 1 }
|
||||
{ "type":10, "val": 1, "subtype": 5, "info": 0 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -33,10 +33,10 @@
|
||||
},
|
||||
"connections" :
|
||||
[
|
||||
{ "a" : "1", "b" : "5", "guard" : 1000 },
|
||||
{ "a" : "2", "b" : "5", "guard" : 1000 },
|
||||
{ "a" : "3", "b" : "5", "guard" : 1000 },
|
||||
{ "a" : "4", "b" : "5", "guard" : 1000 }
|
||||
{ "a" : "1", "b" : "5", "guard" : 5000 },
|
||||
{ "a" : "2", "b" : "5", "guard" : 5000 },
|
||||
{ "a" : "3", "b" : "5", "guard" : 5000 },
|
||||
{ "a" : "4", "b" : "5", "guard" : 5000 }
|
||||
]
|
||||
},
|
||||
"Upgrade" :
|
||||
@ -111,18 +111,18 @@
|
||||
},
|
||||
"connections" :
|
||||
[
|
||||
{ "a" : "1", "b" : "4", "guard" : 1000 },
|
||||
{ "a" : "1", "b" : "5", "guard" : 1000 },
|
||||
{ "a" : "2", "b" : "6", "guard" : 1000 },
|
||||
{ "a" : "2", "b" : "7", "guard" : 1000 },
|
||||
{ "a" : "3", "b" : "8", "guard" : 1000 },
|
||||
{ "a" : "3", "b" : "9", "guard" : 1000 },
|
||||
{ "a" : "4", "b" : "10", "guard" : 1000 },
|
||||
{ "a" : "5", "b" : "12", "guard" : 1000 },
|
||||
{ "a" : "6", "b" : "10", "guard" : 1000 },
|
||||
{ "a" : "7", "b" : "11", "guard" : 1000 },
|
||||
{ "a" : "8", "b" : "12", "guard" : 1000 },
|
||||
{ "a" : "9", "b" : "11", "guard" : 1000 }
|
||||
{ "a" : "1", "b" : "4", "guard" : 2000 },
|
||||
{ "a" : "1", "b" : "5", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "6", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "7", "guard" : 2000 },
|
||||
{ "a" : "3", "b" : "8", "guard" : 2000 },
|
||||
{ "a" : "3", "b" : "9", "guard" : 2000 },
|
||||
{ "a" : "4", "b" : "10", "guard" : 20000 },
|
||||
{ "a" : "5", "b" : "12", "guard" : 20000 },
|
||||
{ "a" : "6", "b" : "10", "guard" : 20000 },
|
||||
{ "a" : "7", "b" : "11", "guard" : 20000 },
|
||||
{ "a" : "8", "b" : "12", "guard" : 20000 },
|
||||
{ "a" : "9", "b" : "11", "guard" : 20000 }
|
||||
]
|
||||
},
|
||||
"Unfair Game" :
|
||||
@ -156,12 +156,12 @@
|
||||
},
|
||||
"connections" :
|
||||
[
|
||||
{ "a" : "1", "b" : "3", "guard" : 2000 },
|
||||
{ "a" : "1", "b" : "4", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "3", "guard" : 2000 },
|
||||
{ "a" : "2", "b" : "4", "guard" : 2000 },
|
||||
{ "a" : "3", "b" : "5", "guard" : 1000 },
|
||||
{ "a" : "4", "b" : "6", "guard" : 1000 }
|
||||
{ "a" : "1", "b" : "3", "guard" : 5000 },
|
||||
{ "a" : "1", "b" : "4", "guard" : 5000 },
|
||||
{ "a" : "2", "b" : "3", "guard" : 5000 },
|
||||
{ "a" : "2", "b" : "4", "guard" : 5000 },
|
||||
{ "a" : "3", "b" : "5", "guard" : 2000 },
|
||||
{ "a" : "4", "b" : "6", "guard" : 2000 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -105,8 +105,7 @@
|
||||
"additionalProperties" : false,
|
||||
"required" : [
|
||||
"adventureMap", "buildingsIcons", "buildings", "creatures", "guildWindow", "names",
|
||||
"hallBackground", "hallSlots", "horde", "mageGuild", "moatDamage", "defaultTavern",
|
||||
"musicTheme", "siege", "structures", "townBackground", "warMachine"
|
||||
"hallBackground", "hallSlots", "horde", "mageGuild", "moatDamage", "defaultTavern", "tavernVideo", "guildBackground", "musicTheme", "siege", "structures", "townBackground", "warMachine"
|
||||
],
|
||||
"description": "town",
|
||||
"properties":{
|
||||
@ -168,6 +167,11 @@
|
||||
"minimum" : 0
|
||||
}
|
||||
},
|
||||
"tavernVideo" : {
|
||||
"type" : "string",
|
||||
"description" : "Video for tavern window",
|
||||
"format" : "videoFile"
|
||||
},
|
||||
"names" : {
|
||||
"type" : "array",
|
||||
"description" : "Names for towns on adventure map",
|
||||
@ -199,6 +203,12 @@
|
||||
"type":"string",
|
||||
"description": "Image with small view on town from mage guild"
|
||||
},
|
||||
"guildBackground": {
|
||||
"type":"string",
|
||||
"description": "Image with background of mage guild",
|
||||
"format" : "imageFile"
|
||||
},
|
||||
|
||||
"hallBackground": {
|
||||
"type":"string",
|
||||
"description": "background image for town hall",
|
||||
|
31
config/schemas/object.json
Normal file
31
config/schemas/object.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"type":"object",
|
||||
"$schema": "http://json-schema.org/draft-04/schema",
|
||||
"title" : "VCMI map object format",
|
||||
"description" : "Description of map object class",
|
||||
"required": [ "handler", "name" ],
|
||||
"additionalProperties" : false,
|
||||
|
||||
"properties":{
|
||||
"index": {
|
||||
"type":"number",
|
||||
},
|
||||
"name": {
|
||||
"type":"string",
|
||||
},
|
||||
|
||||
"handler": {
|
||||
"type":"string",
|
||||
},
|
||||
|
||||
"base": {
|
||||
"$ref" : "vcmi:objectType"
|
||||
},
|
||||
"types": {
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"$ref" : "vcmi:objectType"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
27
config/schemas/objectType.json
Normal file
27
config/schemas/objectType.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"type":"object",
|
||||
"$schema": "http://json-schema.org/draft-04/schema",
|
||||
"title" : "VCMI map object type format",
|
||||
"description" : "Description of map object type, used only as sub-schema of object",
|
||||
"required": [ ],
|
||||
"additionalProperties" : true, // may have type-dependant properties
|
||||
|
||||
"properties":{
|
||||
"index": {
|
||||
"type":"number",
|
||||
},
|
||||
"name": {
|
||||
"type":"string",
|
||||
},
|
||||
|
||||
"base": {
|
||||
"$ref" : "vcmi:objectTemplate"
|
||||
},
|
||||
"types": {
|
||||
"type":"object",
|
||||
"additionalProperties": {
|
||||
"$ref" : "vcmi:objectTemplate"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -176,9 +176,12 @@
|
||||
},
|
||||
"limit":{
|
||||
"$ref" : "#/definitions/flags",
|
||||
"description": "flags structure of bonus names, presence of all bonuses required to be affected by"
|
||||
"description": "flags structure of bonus names, presence of all bonuses required to be affected by."
|
||||
},
|
||||
"absoluteLimit":{
|
||||
"$ref" : "#/definitions/flags",
|
||||
"description": "flags structure of bonus names, presence of all bonuses required to be affected by, can't be negated."
|
||||
},
|
||||
|
||||
"graphics":{
|
||||
"type": "object",
|
||||
"additionalProperties" : false,
|
||||
@ -229,6 +232,11 @@
|
||||
"required" : ["none", "basic", "advanced", "expert"],
|
||||
|
||||
"properties":{
|
||||
"base":{
|
||||
"type": "object",
|
||||
"description": "will be merged with all levels",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"none":{
|
||||
"$ref" : "#/definitions/levelInfo"
|
||||
},
|
||||
|
@ -63,6 +63,21 @@
|
||||
"gems": { "type":"number"},
|
||||
"gold": { "type":"number"}
|
||||
}
|
||||
},
|
||||
"produce": {
|
||||
"type":"object",
|
||||
"additionalProperties" : false,
|
||||
"description": "Resources this building produce each day",
|
||||
"properties":{
|
||||
"wood": { "type":"number"},
|
||||
"mercury": { "type":"number"},
|
||||
"ore": { "type":"number"},
|
||||
"sulfur": { "type":"number"},
|
||||
"crystal": { "type":"number"},
|
||||
"gems": { "type":"number"},
|
||||
"gold": { "type":"number"}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
300
config/spells/ability.json
Normal file
300
config/spells/ability.json
Normal file
@ -0,0 +1,300 @@
|
||||
{
|
||||
"stoneGaze" : {
|
||||
"index" : 70,
|
||||
"anim" : 70,
|
||||
"sounds": {
|
||||
"cast": "PARALYZE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true},
|
||||
"effects" : {
|
||||
"notActive" : {
|
||||
"val" : 0,
|
||||
"type" : "NOT_ACTIVE",
|
||||
"subtype" : 62,
|
||||
"duration" : [
|
||||
"UNITL_BEING_ATTACKED",
|
||||
"N_TURNS"
|
||||
]
|
||||
},
|
||||
"noRetaliation" : {
|
||||
"val" : 0,
|
||||
"type" : "NO_RETALIATION",
|
||||
"duration" : "UNITL_BEING_ATTACKED"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"poison" : {
|
||||
"index" : 71,
|
||||
"anim" : 67,
|
||||
"sounds": {
|
||||
"cast": "POISON"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true},
|
||||
"effects" : {
|
||||
"poison" : {
|
||||
"val" : 30,
|
||||
"type" : "POISON",
|
||||
"valueType" : "INDEPENDENT_MAX",
|
||||
"duration" : "N_TURNS"
|
||||
},
|
||||
"stackHealth" : {
|
||||
"val" : -10,
|
||||
"type" : "STACK_HEALTH",
|
||||
"valueType" : "PERCENT_TO_ALL",
|
||||
"duration" : "N_TURNS"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"immunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
},
|
||||
"flags" : {
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"bind" : {
|
||||
"index" : 72,
|
||||
"anim" : 68,
|
||||
"sounds": {
|
||||
"cast": "BIND"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"effects" : {
|
||||
"bindEffect" : {
|
||||
"val" : 0,
|
||||
"type" : "BIND_EFFECT",
|
||||
"duration" : "PERMANENT",
|
||||
"addInfo" : -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"disease" : {
|
||||
"index" : 73,
|
||||
"anim" : 69,
|
||||
"sounds": {
|
||||
"cast": "DISEASE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true},
|
||||
"effects" : {
|
||||
"attack" : {
|
||||
"val" : -2,
|
||||
"type" : "PRIMARY_SKILL",
|
||||
"subtype" : "primSkill.attack",
|
||||
"duration" : "N_TURNS"
|
||||
},
|
||||
"defence" : {
|
||||
"val" : -2,
|
||||
"type" : "PRIMARY_SKILL",
|
||||
"subtype" : "primSkill.defence",
|
||||
"duration" : "N_TURNS"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"immunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
},
|
||||
"flags" : {
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"paralyze" : {
|
||||
"index" : 74,
|
||||
"anim" : 70,
|
||||
"sounds": {
|
||||
"cast": "PARALYZE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true},
|
||||
"effects" : {
|
||||
"notActive" : {
|
||||
"val" : 0,
|
||||
"type" : "NOT_ACTIVE",
|
||||
"subtype" : 74,
|
||||
"duration" : [
|
||||
"UNITL_BEING_ATTACKED",
|
||||
"N_TURNS"
|
||||
]
|
||||
},
|
||||
"noRetaliation" : {
|
||||
"val" : 0,
|
||||
"type" : "NO_RETALIATION",
|
||||
"duration" : "UNITL_BEING_ATTACKED"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"age" : {
|
||||
"index" : 75,
|
||||
"anim" : 71,
|
||||
"sounds": {
|
||||
"cast": "AGE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true},
|
||||
"effects" : {
|
||||
"stackHealth" : {
|
||||
"val" : -50,
|
||||
"type" : "STACK_HEALTH",
|
||||
"valueType" : "PERCENT_TO_ALL",
|
||||
"duration" : "N_TURNS"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"immunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
},
|
||||
"flags" : {
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"deathCloud" : {
|
||||
"index" : 76,
|
||||
"anim" : 72,
|
||||
"sounds": {
|
||||
"cast": "DEATHCLD"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0-1"
|
||||
}
|
||||
},
|
||||
"immunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"thunderbolt" : {
|
||||
"index" : 77,
|
||||
"anim" : 38,
|
||||
"sounds": {
|
||||
"cast": "LIGHTBLT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"dispelHelpful" : {
|
||||
"index" : 78,
|
||||
"anim" : 41,
|
||||
"sounds": {
|
||||
"cast": "DISPELL"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
}
|
||||
},
|
||||
|
||||
"flags" : {
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"deathStare" : {
|
||||
"index" : 79,
|
||||
"anim" : 80,
|
||||
"sounds": {
|
||||
"cast": "DEATHSTR"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
}
|
||||
},
|
||||
"absoluteImmunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"acidBreath" : {
|
||||
"index" : 80,
|
||||
"anim" : 81,
|
||||
"sounds": {
|
||||
"cast": "ACID"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true},
|
||||
"effects" : {
|
||||
"primarySkill" : {
|
||||
"val" : -3,
|
||||
"type" : "PRIMARY_SKILL",
|
||||
"subtype" : "primSkill.attack",
|
||||
"duration" : "PERMANENT",
|
||||
"valueType" : "ADDITIVE_VALUE"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"acidBreathDamage" : {
|
||||
"index" : 81,
|
||||
"anim" : 81,
|
||||
"sounds": {
|
||||
"cast": "ACID"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"indifferent": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
}
|
||||
}
|
152
config/spells/adventure.json
Normal file
152
config/spells/adventure.json
Normal file
@ -0,0 +1,152 @@
|
||||
{
|
||||
"summonBoat" : {
|
||||
"index" : 0,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "SUMMBOAT"
|
||||
},
|
||||
"levels" :{
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"scuttleBoat" : {
|
||||
"index" : 1,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "SCUTBOAT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"visions" : {
|
||||
"index" : 2,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "VISIONS"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"viewEarth" : {
|
||||
"index" : 3,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "VIEW"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"disguise" : {
|
||||
"index" : 4,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "DISGUISE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"viewAir" : {
|
||||
"index" : 5,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "VIEW"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"fly" : {
|
||||
"index" : 6,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "FLYSPELL"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"waterWalk" : {
|
||||
"index" : 7,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "WATRWALK"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"dimensionDoor" : {
|
||||
"index" : 8,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "TELPTOUT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"townPortal" : {
|
||||
"index" : 9,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "TELPTOUT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
}
|
||||
}
|
281
config/spells/offensive.json
Normal file
281
config/spells/offensive.json
Normal file
@ -0,0 +1,281 @@
|
||||
{
|
||||
"magicArrow" : {
|
||||
"index" : 15,
|
||||
"anim" : 64,
|
||||
"sounds": {
|
||||
"cast": "MAGICBLT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"iceBolt" : {
|
||||
"index" : 16,
|
||||
"anim" : 46,
|
||||
"sounds": {
|
||||
"cast": "ICERAY"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"lightningBolt" : {
|
||||
"index" : 17,
|
||||
"anim" : 38,
|
||||
"sounds": {
|
||||
"cast": "LIGHTBLT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"implosion" : {
|
||||
"index" : 18,
|
||||
"anim" : 10,
|
||||
"sounds": {
|
||||
"cast": "DECAY"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"chainLightning" : {
|
||||
"index" : 19,
|
||||
"anim" : 38,
|
||||
"sounds": {
|
||||
"cast": "CHAINLTE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
}
|
||||
},
|
||||
"frostRing" : {
|
||||
"index" : 20,
|
||||
"anim" : 45,
|
||||
"sounds": {
|
||||
"cast": "FROSTING"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "1",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"fireball" : {
|
||||
"index" : 21,
|
||||
"anim" : 53,
|
||||
"sounds": {
|
||||
"cast": "FIREBALL"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0,1",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"inferno" : {
|
||||
"index" : 22,
|
||||
"anim" : 9,
|
||||
"sounds": {
|
||||
"cast": "FIREBLST"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0-2",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"meteorShower" : {
|
||||
"index" : 23,
|
||||
"anim" : 16,
|
||||
"sounds": {
|
||||
"cast": "METEOR"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0,1",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"deathRipple" : {
|
||||
"index" : 24,
|
||||
"targetType" : "CREATURE",
|
||||
"anim" : 8,
|
||||
"sounds": {
|
||||
"cast": "DEATHRIP"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"absoluteImmunity":{
|
||||
"UNDEAD": true,
|
||||
},
|
||||
"immunity" : {
|
||||
"SIEGE_WEAPON": true,
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"destroyUndead" : {
|
||||
"index" : 25,
|
||||
"targetType" : "CREATURE",
|
||||
"anim" : 29,
|
||||
"sounds": {
|
||||
"cast": "COLDRING"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"absoluteLimit" : {
|
||||
"UNDEAD": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"armageddon" : {
|
||||
"index" : 26,
|
||||
"targetType" : "CREATURE",
|
||||
"anim" : 12,
|
||||
"sounds": {
|
||||
"cast": "ARMGEDN"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"titanBolt" : {
|
||||
"index" : 57,
|
||||
"anim" : 38,
|
||||
"sounds": {
|
||||
"cast": "LIGHTBLT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"offensive": true,
|
||||
"negative": true,
|
||||
"special": true
|
||||
}
|
||||
},
|
||||
}
|
298
config/spells/other.json
Normal file
298
config/spells/other.json
Normal file
@ -0,0 +1,298 @@
|
||||
{
|
||||
"quicksand" : {
|
||||
"index" : 10,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "QUIKSAND"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"landMine" : {
|
||||
"index" : 11,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": ""
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"indifferent": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"forceField" : {
|
||||
"index" : 12,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "FORCEFLD"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"fireWall" : {
|
||||
"index" : 13,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "FIREWALL"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"damage": true,
|
||||
"indifferent": true
|
||||
},
|
||||
"immunity" : {
|
||||
"DIRECT_DAMAGE_IMMUNITY": true
|
||||
}
|
||||
},
|
||||
"earthquake" : {
|
||||
"index" : 14,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "ERTHQUAK"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
|
||||
"dispel" : {
|
||||
"index" : 35,
|
||||
"anim" : 41,
|
||||
"sounds": {
|
||||
"cast": "DISPELL"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0"
|
||||
},
|
||||
"expert":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"cure" : {
|
||||
"index" : 37,
|
||||
"anim" : 39,
|
||||
"sounds": {
|
||||
"cast": "CURE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"targetModifier":{"smart":true},
|
||||
"range" : "0"
|
||||
},
|
||||
"expert":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"positive": true
|
||||
}
|
||||
},
|
||||
"resurrection" : {
|
||||
"index" : 38,
|
||||
"anim" : 79,
|
||||
"sounds": {
|
||||
"cast": "RESURECT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"rising": true,
|
||||
"positive": true
|
||||
},
|
||||
"absoluteImmunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
}
|
||||
},
|
||||
"animateDead" : {
|
||||
"index" : 39,
|
||||
"anim" : 79,
|
||||
"sounds": {
|
||||
"cast": "ANIMDEAD"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"rising": true,
|
||||
"positive": true
|
||||
},
|
||||
"absoluteLimit" : {
|
||||
"UNDEAD": true
|
||||
}
|
||||
},
|
||||
"sacrifice" : {
|
||||
"index" : 40,
|
||||
"anim" : 79,
|
||||
"sounds": {
|
||||
"cast": "SACRIF1"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"rising": true,
|
||||
"positive": true
|
||||
},
|
||||
"absoluteImmunity" : {
|
||||
"UNDEAD": true,
|
||||
"NON_LIVING": true
|
||||
}
|
||||
},
|
||||
"teleport" : {
|
||||
"index" : 63,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "TELPTOUT"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":false}
|
||||
}
|
||||
},
|
||||
"immunity" : {
|
||||
"SIEGE_WEAPON": true
|
||||
},
|
||||
"flags" : {
|
||||
"positive": true
|
||||
}
|
||||
},
|
||||
"removeObstacle" : {
|
||||
"index" : 64,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "REMOVEOB"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"clone" : {
|
||||
"index" : 65,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "CLONE"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "0",
|
||||
"targetModifier":{"smart":true}
|
||||
}
|
||||
},
|
||||
"immunity" : {
|
||||
"SIEGE_WEAPON": true
|
||||
},
|
||||
"flags" : {
|
||||
"positive": true
|
||||
}
|
||||
},
|
||||
"fireElemental" : {
|
||||
"index" : 66,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"earthElemental" : {
|
||||
"index" : 67,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"waterElemental" : {
|
||||
"index" : 68,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
},
|
||||
"airElemental" : {
|
||||
"index" : 69,
|
||||
"anim" : -1,
|
||||
"sounds": {
|
||||
"cast": "SUMNELM"
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
"flags" : {
|
||||
"indifferent": true
|
||||
}
|
||||
}
|
||||
}
|
1204
config/spells/timed.json
Normal file
1204
config/spells/timed.json
Normal file
File diff suppressed because it is too large
Load Diff
2
debian/control
vendored
2
debian/control
vendored
@ -5,6 +5,8 @@ Maintainer: Ivan Savenko <saven.ivan@gmail.com>
|
||||
Build-Depends: debhelper (>= 8), cmake, libsdl-image1.2-dev, libsdl-ttf2.0-dev, libsdl-mixer1.2-dev (>= 1.2.8), zlib1g-dev, libavformat-dev, libswscale-dev, libboost-dev (>=1.48), libboost-program-options-dev (>=1.48), libboost-filesystem-dev (>=1.48), libboost-system-dev (>=1.48), libboost-locale-dev (>=1.48), libboost-thread-dev (>=1.48), qtbase5-dev
|
||||
Standards-Version: 3.9.1
|
||||
Homepage: http://vcmi.eu
|
||||
Vcs-Git: git://github.com/vcmi/vcmi.git
|
||||
Vcs-Browser: https://github.com/vcmi/vcmi
|
||||
|
||||
Package: vcmi
|
||||
Architecture: any
|
||||
|
2
debian/docs
vendored
2
debian/docs
vendored
@ -1,2 +0,0 @@
|
||||
NEWS
|
||||
README
|
@ -19,13 +19,13 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120_xp</PlatformToolset>
|
||||
<PlatformToolset>v110</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@ -44,16 +44,17 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<IncludePath>.\GeneratedFiles;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QtDir)\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(QtDir)\lib;$(LibraryPath)</LibraryPath>
|
||||
<IncludePath>.\GeneratedFiles;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtGui;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtCore;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtANGLE;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtWidgets;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include;$(IncludePath)</IncludePath>
|
||||
<LibraryPath>D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\lib;$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
<LinkIncremental>
|
||||
</LinkIncremental>
|
||||
<IncludePath>.\GeneratedFiles;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtCore;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QtDir)\include;$(IncludePath)</IncludePath>
|
||||
<IncludePath>.\GeneratedFiles;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtGui;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtCore;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtANGLE;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtWidgets;D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include;$(IncludePath)</IncludePath>
|
||||
<CustomBuildBeforeTargets>
|
||||
</CustomBuildBeforeTargets>
|
||||
<LibraryPath>$(QtDir)\lib;$(LibraryPath)</LibraryPath>
|
||||
<LibraryPath>D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\lib;$(LibraryPath)</LibraryPath>
|
||||
<OutDir>..</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
@ -64,6 +65,7 @@
|
||||
<Link />
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5Networkd.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\libs;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">
|
||||
@ -72,9 +74,11 @@
|
||||
<Optimization>Full</Optimization>
|
||||
<PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
|
||||
<AdditionalOptions>/Zm150 %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>VCMI_lib.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5Network.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>..\..\libs;..</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<CustomBuildStep>
|
||||
<Command>
|
||||
@ -120,42 +124,42 @@
|
||||
<ClInclude Include=".\**\*.h" Exclude=".\**\*_moc.h" />
|
||||
<ClInclude Include="GeneratedFiles\*.h" />
|
||||
<CustomBuild Include=".\**\*_moc.h" Exclude=".\**\ui_*.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing %(Filename) file...</Message>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Calling D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe for %(Filename) file...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Moc%27ing %(Filename) file...</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtCore" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtGui" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtWidgets" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Calling D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe for %(Filename) file...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Moc%27ing some file...</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtCore" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtGui" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtWidgets" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Calling D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe for %(Filename) file...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Moc%27ing %(Filename) file...</Message>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtCore" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtGui" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtWidgets" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtSvg"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|x64'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Calling D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe for %(Filename) file...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='RD|x64'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|x64'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I$(QTDIR)\include\QtCore" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtSvg"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|x64'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fStdInc.h" "-f..\..\%(RecursiveDir)%(Filename).h" -DUNICODE -DWIN32 -DWIN64 -DQT_DLL -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQT_GUI_LIB -DQT_WIDGETS_LIB -DQT_SVG_LIB "-I.\GeneratedFiles" "-I." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtCore" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtGui" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtWidgets" "-ID:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\include\QtSvg"</Command>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<CustomBuild Include=".\**\*.ui">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|x64'">$(QTDIR)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='RD|x64'">D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='RD|x64'">Uic%27ing %(Identity)...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='RD|x64'">.\GeneratedFiles\ui_%(Filename).h;%(Outputs)</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|x64'">"$(QTDIR)\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='RD|x64'">"D:\Programowanie\Biblioteki\QT\5.1.1\msvc2012\bin\uic.exe" -o ".\GeneratedFiles\ui_%(Filename).h" "%(FullPath)"</Command>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -87,7 +87,7 @@ std::pair< std::vector<BattleHex>, int > BattleInfo::getPath(BattleHex start, Ba
|
||||
}
|
||||
|
||||
ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero,
|
||||
bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg )
|
||||
bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg, CRandomGenerator & rand )
|
||||
{
|
||||
TDmgRange range = calculateDmgRange(attacker, defender, shooting, charge, lucky, unlucky, deathBlow, ballistaDoubleDmg);
|
||||
|
||||
@ -97,7 +97,7 @@ ui32 BattleInfo::calculateDmg( const CStack* attacker, const CStack* defender, c
|
||||
int howManyToAv = std::min<ui32>(10, attacker->count);
|
||||
for (int g=0; g<howManyToAv; ++g)
|
||||
{
|
||||
valuesToAverage[g] = range.first + rand() % (range.second - range.first + 1);
|
||||
valuesToAverage[g] = rand.nextInt(range.first, range.second);
|
||||
}
|
||||
|
||||
return std::accumulate(valuesToAverage, valuesToAverage + howManyToAv, 0) / howManyToAv;
|
||||
@ -723,40 +723,6 @@ const CGHeroInstance * BattleInfo::getHero( PlayerColor player ) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<ui32> BattleInfo::calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::vector<const CStack*> & affectedCreatures, PlayerColor casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const
|
||||
{
|
||||
std::vector<ui32> ret;
|
||||
for(auto & affectedCreature : affectedCreatures)
|
||||
{
|
||||
if(battleIsImmune(caster, sp, mode, (affectedCreature)->position) != ESpellCastProblem::OK) //FIXME: immune stacks should not display resisted animation
|
||||
{
|
||||
ret.push_back((affectedCreature)->ID);
|
||||
continue;
|
||||
}
|
||||
|
||||
//non-negative spells should always succeed, unless immune
|
||||
if(!sp->isNegative())// && (*it)->owner == casterSideOwner)
|
||||
continue;
|
||||
|
||||
/*
|
||||
const CGHeroInstance * bonusHero; //hero we should take bonuses from
|
||||
if((*it)->owner == casterSideOwner)
|
||||
bonusHero = caster;
|
||||
else
|
||||
bonusHero = hero2;*/
|
||||
|
||||
int prob = (affectedCreature)->magicResistance(); //probability of resistance in %
|
||||
|
||||
if(prob > 100) prob = 100;
|
||||
|
||||
if(rand()%100 < prob) //immunity from resistance
|
||||
ret.push_back((affectedCreature)->ID);
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PlayerColor BattleInfo::theOtherPlayer(PlayerColor player) const
|
||||
{
|
||||
return sides[!whatSide(player)].color;
|
||||
|
@ -129,7 +129,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
shared_ptr<CObstacleInstance> getObstacleOnTile(BattleHex tile) const;
|
||||
std::set<BattleHex> getStoppers(bool whichSidePerspective) const;
|
||||
|
||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool unlucky, bool deathBlow, bool ballistaDoubleDmg, CRandomGenerator & rand); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||
|
||||
//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
||||
@ -144,8 +144,6 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
|
||||
const CGHeroInstance * getHero(PlayerColor player) const; //returns fighting hero that belongs to given player
|
||||
|
||||
std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHeroInstance * caster, const CGHeroInstance * hero2, const std::vector<const CStack*> & affectedCreatures, PlayerColor casterSideOwner, ECastingMode::ECastingMode mode, int usedSpellPower, int spellLevel) const;
|
||||
|
||||
const CStack * battleGetStack(BattleHex pos, bool onlyAlive); //returns stack at given tile
|
||||
const CGHeroInstance * battleGetOwner(const CStack * stack) const; //returns hero that owns given stack; nullptr if none
|
||||
void localInit();
|
||||
|
@ -177,29 +177,36 @@ bool CBattleInfoEssentials::battleHasNativeStack(ui8 side) const
|
||||
return false;
|
||||
}
|
||||
|
||||
TStacks CBattleInfoEssentials::battleGetAllStacks(bool includeTurrets /*= false*/) const /*returns all stacks, alive or dead or undead or mechanical :) */
|
||||
TStacks CBattleInfoEssentials::battleGetAllStacks(bool includeTurrets /*= false*/) const
|
||||
{
|
||||
return battleGetStacksIf([](const CStack * s){return true;},includeTurrets);
|
||||
}
|
||||
|
||||
TStacks CBattleInfoEssentials::battleGetStacksIf(TStackFilter predicate, bool includeTurrets /*= false*/) const
|
||||
{
|
||||
TStacks ret;
|
||||
RETURN_IF_NOT_BATTLE(ret);
|
||||
boost::copy(getBattle()->stacks, std::back_inserter(ret));
|
||||
if(!includeTurrets)
|
||||
vstd::erase_if(ret, [](const CStack *stack) { return stack->type->idNumber == CreatureID::ARROW_TOWERS; });
|
||||
|
||||
vstd::copy_if(getBattle()->stacks, std::back_inserter(ret), [=](const CStack * s){
|
||||
return predicate(s) && (includeTurrets || !(s->type->idNumber == CreatureID::ARROW_TOWERS));
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
TStacks CBattleInfoEssentials::battleAliveStacks() const
|
||||
{
|
||||
TStacks ret;
|
||||
vstd::copy_if(battleGetAllStacks(), std::back_inserter(ret), [](const CStack *s){ return s->alive(); });
|
||||
return ret;
|
||||
return battleGetStacksIf([](const CStack * s){
|
||||
return s->alive();
|
||||
});
|
||||
}
|
||||
|
||||
TStacks CBattleInfoEssentials::battleAliveStacks(ui8 side) const
|
||||
{
|
||||
TStacks ret;
|
||||
vstd::copy_if(battleGetAllStacks(), std::back_inserter(ret), [=](const CStack *s){ return s->alive() && s->attackerOwned == !side; });
|
||||
return ret;
|
||||
return battleGetStacksIf([=](const CStack * s){
|
||||
return s->alive() && s->attackerOwned == !side;
|
||||
});
|
||||
}
|
||||
|
||||
int CBattleInfoEssentials::battleGetMoatDmg() const
|
||||
@ -1562,11 +1569,58 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C
|
||||
{
|
||||
RETURN_IF_NOT_BATTLE(ESpellCastProblem::INVALID);
|
||||
|
||||
// Get stack at destination hex -> subject of our spell.
|
||||
const CStack * subject = battleGetStackByPos(dest, !spell->isRisingSpell()); //only alive if not rising spell
|
||||
// Get all stacks at destination hex -> subject of our spell. only alive if not rising spell
|
||||
TStacks stacks = battleGetStacksIf([=](const CStack * s){
|
||||
return s->coversPos(dest) && (spell->isRisingSpell() || s->alive());
|
||||
});
|
||||
|
||||
if(subject)
|
||||
if(!stacks.empty())
|
||||
{
|
||||
bool allImmune = true;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem problem;
|
||||
|
||||
for(auto s : stacks)
|
||||
{
|
||||
ESpellCastProblem::ESpellCastProblem res = battleStackIsImmune(caster,spell,mode,s);
|
||||
|
||||
if(res == ESpellCastProblem::OK)
|
||||
{
|
||||
allImmune = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
problem = res;
|
||||
}
|
||||
}
|
||||
|
||||
if(allImmune)
|
||||
return problem;
|
||||
}
|
||||
else //no target stack on this tile
|
||||
{
|
||||
if(spell->getTargetType() == CSpell::CREATURE)
|
||||
{
|
||||
if(caster && mode == ECastingMode::HERO_CASTING) //TODO why???
|
||||
{
|
||||
const CSpell::TargetInfo ti = spell->getTargetInfo(caster->getSpellSchoolLevel(spell));
|
||||
|
||||
if(!ti.massive)
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleStackIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, const CStack * subject) const
|
||||
{
|
||||
if (spell->isPositive() && subject->hasBonusOfType(Bonus::RECEPTIVE)) //accept all positive spells
|
||||
return ESpellCastProblem::OK;
|
||||
|
||||
@ -1643,25 +1697,6 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C
|
||||
if (subjectHealth > maxHealth)
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
}
|
||||
else //no target stack on this tile
|
||||
{
|
||||
if(spell->getTargetType() == CSpell::CREATURE)
|
||||
{
|
||||
if(caster && mode == ECastingMode::HERO_CASTING) //TODO why???
|
||||
{
|
||||
const CSpell::TargetInfo ti = spell->getTargetInfo(caster->getSpellSchoolLevel(spell));
|
||||
|
||||
if(!ti.massive)
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ESpellCastProblem::WRONG_SPELL_TARGET;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
@ -1708,7 +1743,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
||||
auto stacks = spell->isNegative() ? battleAliveStacks(!side) : battleAliveStacks();
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
if(!battleIsImmune(castingHero, spell, mode, stack->position))
|
||||
if( ESpellCastProblem::OK == battleStackIsImmune(castingHero, spell, mode, stack))
|
||||
{
|
||||
allStacksImmune = false;
|
||||
break;
|
||||
@ -1750,7 +1785,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
||||
bool targetExists = false;
|
||||
for(const CStack * stack : battleGetAllStacks()) //dead stacks will be immune anyway
|
||||
{
|
||||
bool immune = battleIsImmune(caster, spell, mode, stack->position) != ESpellCastProblem::OK;
|
||||
bool immune = ESpellCastProblem::OK != battleStackIsImmune(caster, spell, mode, stack);
|
||||
bool casterStack = stack->owner == caster->getOwner();
|
||||
|
||||
if(!immune)
|
||||
@ -1805,7 +1840,7 @@ std::vector<BattleHex> CBattleInfoCallback::battleGetPossibleTargets(PlayerColor
|
||||
|
||||
for(const CStack * stack : battleAliveStacks())
|
||||
{
|
||||
bool immune = battleIsImmune(caster, spell, mode, stack->position) != ESpellCastProblem::OK;
|
||||
bool immune = ESpellCastProblem::OK != battleStackIsImmune(caster, spell, mode, stack);
|
||||
bool casterStack = stack->owner == caster->getOwner();
|
||||
|
||||
if(!immune)
|
||||
@ -2018,28 +2053,14 @@ ui32 CBattleInfoCallback::calculateSpellDmg( const CSpell * sp, const CGHeroInst
|
||||
|
||||
std::set<const CStack*> CBattleInfoCallback::getAffectedCreatures(const CSpell * spell, int skillLevel, PlayerColor attackerOwner, BattleHex destinationTile)
|
||||
{
|
||||
std::set<const CStack*> attackedCres; /*std::set to exclude multiple occurrences of two hex creatures*/
|
||||
std::set<const CStack*> attackedCres; //std::set to exclude multiple occurrences of two hex creatures
|
||||
|
||||
const ui8 attackerSide = playerToSide(attackerOwner) == 1;
|
||||
const auto attackedHexes = spell->rangeInHexes(destinationTile, skillLevel, attackerSide);
|
||||
const bool onlyAlive = !spell->isRisingSpell(); //when casting resurrection or animate dead we should be allow to select dead stack
|
||||
|
||||
const CSpell::TargetInfo ti = spell->getTargetInfo(skillLevel);
|
||||
//TODO: more generic solution for mass spells
|
||||
if(spell->id == SpellID::DEATH_RIPPLE || spell->id == SpellID::DESTROY_UNDEAD )
|
||||
{
|
||||
for(const CStack *stack : battleGetAllStacks())
|
||||
{
|
||||
if((spell->id == SpellID::DEATH_RIPPLE && !stack->getCreature()->isUndead()) //death ripple
|
||||
|| (spell->id == SpellID::DESTROY_UNDEAD && stack->getCreature()->isUndead()) //destroy undead
|
||||
)
|
||||
{
|
||||
if(stack->isValidTarget())
|
||||
attackedCres.insert(stack);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (spell->id == SpellID::CHAIN_LIGHTNING)
|
||||
if (spell->id == SpellID::CHAIN_LIGHTNING)
|
||||
{
|
||||
std::set<BattleHex> possibleHexes;
|
||||
for (auto stack : battleGetAllStacks())
|
||||
@ -2074,7 +2095,7 @@ std::set<const CStack*> CBattleInfoCallback::getAffectedCreatures(const CSpell *
|
||||
{
|
||||
for(BattleHex hex : attackedHexes)
|
||||
{
|
||||
if(const CStack * st = battleGetStackByPos(hex, onlyAlive))
|
||||
if(const CStack * st = battleGetStackByPos(hex, ti.onlyAlive))
|
||||
{
|
||||
if (spell->id == SpellID::DEATH_CLOUD) //Death Cloud //TODO: fireball and fire immunity
|
||||
{
|
||||
@ -2090,38 +2111,51 @@ std::set<const CStack*> CBattleInfoCallback::getAffectedCreatures(const CSpell *
|
||||
}
|
||||
else if(spell->getTargetType() == CSpell::CREATURE)
|
||||
{
|
||||
auto predicate = [=](const CStack * s){
|
||||
const bool positiveToAlly = spell->isPositive() && s->owner == attackerOwner;
|
||||
const bool negativeToEnemy = spell->isNegative() && s->owner != attackerOwner;
|
||||
const bool validTarget = s->isValidTarget(!ti.onlyAlive); //todo: this should be handled by spell class
|
||||
|
||||
//for single target spells select stacks covering destination tile
|
||||
const bool rangeCovers = ti.massive || s->coversPos(destinationTile);
|
||||
//handle smart targeting
|
||||
const bool positivenessFlag = !ti.smart || spell->isNeutral() || positiveToAlly || negativeToEnemy;
|
||||
|
||||
return rangeCovers && positivenessFlag && validTarget;
|
||||
};
|
||||
|
||||
TStacks stacks = battleGetStacksIf(predicate);
|
||||
|
||||
if (ti.massive)
|
||||
{
|
||||
TStacks stacks = battleGetAllStacks();
|
||||
|
||||
vstd::erase_if(stacks,[&](const CStack * stack){
|
||||
return ti.smart && spell->isNegative() && stack->owner == attackerOwner;
|
||||
});
|
||||
|
||||
vstd::erase_if(stacks,[&](const CStack * stack){
|
||||
return ti.smart && spell->isPositive() && stack->owner != attackerOwner;
|
||||
});
|
||||
|
||||
vstd::erase_if(stacks,[&](const CStack * stack){
|
||||
return !stack->isValidTarget(!onlyAlive);
|
||||
});
|
||||
|
||||
//for massive spells add all targets
|
||||
for (auto stack : stacks)
|
||||
attackedCres.insert(stack);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if(const CStack * st = battleGetStackByPos(destinationTile, onlyAlive))
|
||||
attackedCres.insert(st);
|
||||
//for single target spells we must select one target. Alive stack is preferred (issue #1763)
|
||||
for(auto stack : stacks)
|
||||
{
|
||||
if(stack->alive())
|
||||
{
|
||||
attackedCres.insert(stack);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(attackedCres.empty() && !stacks.empty())
|
||||
{
|
||||
attackedCres.insert(stacks.front());
|
||||
}
|
||||
}
|
||||
}
|
||||
else //custom range from attackedHexes
|
||||
{
|
||||
for(BattleHex hex : attackedHexes)
|
||||
{
|
||||
if(const CStack * st = battleGetStackByPos(hex, onlyAlive))
|
||||
if(const CStack * st = battleGetStackByPos(hex, ti.onlyAlive))
|
||||
attackedCres.insert(st);
|
||||
}
|
||||
}
|
||||
@ -2251,10 +2285,14 @@ SpellID CBattleInfoCallback::getRandomBeneficialSpell(const CStack * subject) co
|
||||
}
|
||||
}
|
||||
|
||||
if (possibleSpells.size())
|
||||
return possibleSpells[rand() % possibleSpells.size()];
|
||||
if(!possibleSpells.empty())
|
||||
{
|
||||
return *RandomGeneratorUtil::nextItem(possibleSpells, gs->getRandomGenerator());
|
||||
}
|
||||
else
|
||||
{
|
||||
return SpellID::NONE;
|
||||
}
|
||||
}
|
||||
|
||||
SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
|
||||
@ -2269,7 +2307,7 @@ SpellID CBattleInfoCallback::getRandomCastedSpell(const CStack * caster) const
|
||||
{
|
||||
totalWeight += std::max(b->additionalInfo, 1); //minimal chance to cast is 1
|
||||
}
|
||||
int randomPos = rand() % totalWeight;
|
||||
int randomPos = gs->getRandomGenerator().nextInt(totalWeight - 1);
|
||||
for(Bonus * b : *bl)
|
||||
{
|
||||
randomPos -= std::max(b->additionalInfo, 1);
|
||||
@ -2431,22 +2469,18 @@ bool CPlayerBattleCallback::battleCanFlee() const
|
||||
|
||||
TStacks CPlayerBattleCallback::battleGetStacks(EStackOwnership whose /*= MINE_AND_ENEMY*/, bool onlyAlive /*= true*/) const
|
||||
{
|
||||
TStacks ret;
|
||||
RETURN_IF_NOT_BATTLE(ret);
|
||||
if(whose != MINE_AND_ENEMY)
|
||||
{
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
}
|
||||
vstd::copy_if(battleGetAllStacks(), std::back_inserter(ret), [=](const CStack *s) -> bool
|
||||
{
|
||||
|
||||
return battleGetStacksIf([=](const CStack * s){
|
||||
const bool ownerMatches = (whose == MINE_AND_ENEMY)
|
||||
|| (whose == ONLY_MINE && s->owner == player)
|
||||
|| (whose == ONLY_ENEMY && s->owner != player);
|
||||
const bool alivenessMatches = s->alive() || !onlyAlive;
|
||||
return ownerMatches && alivenessMatches;
|
||||
});
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CPlayerBattleCallback::battleGetSurrenderCost() const
|
||||
|
@ -31,6 +31,7 @@ namespace BattleSide
|
||||
}
|
||||
|
||||
typedef std::vector<const CStack*> TStacks;
|
||||
typedef std::function<bool(const CStack *)> TStackFilter;
|
||||
|
||||
class CBattleInfoEssentials;
|
||||
|
||||
@ -168,7 +169,15 @@ public:
|
||||
ETerrainType battleTerrainType() const;
|
||||
BFieldType battleGetBattlefieldType() const;
|
||||
std::vector<shared_ptr<const CObstacleInstance> > battleGetAllObstacles(boost::optional<BattlePerspective::BattlePerspective> perspective = boost::none) const; //returns all obstacles on the battlefield
|
||||
TStacks battleGetAllStacks(bool includeTurrets = false) const; //returns all stacks, alive or dead or undead or mechanical :)
|
||||
|
||||
/** @brief Main method for getting battle stacks
|
||||
*
|
||||
* @param predicate Functor that shall return true for desired stack
|
||||
* @return filtered stacks
|
||||
*
|
||||
*/
|
||||
TStacks battleGetStacksIf(TStackFilter predicate, bool includeTurrets = false) const;
|
||||
|
||||
bool battleHasNativeStack(ui8 side) const;
|
||||
int battleGetMoatDmg() const; //what dmg unit will suffer if ending turn in the moat
|
||||
const CGTownInstance * battleGetDefendedTown() const; //returns defended town if current battle is a siege, nullptr instead
|
||||
@ -190,7 +199,12 @@ public:
|
||||
si8 battleGetWallState(int partOfWall) const;
|
||||
|
||||
//helpers
|
||||
///returns all stacks, alive or dead or undead or mechanical :)
|
||||
TStacks battleGetAllStacks(bool includeTurrets = false) const;
|
||||
|
||||
///returns all alive stacks excluding turrets
|
||||
TStacks battleAliveStacks() const;
|
||||
///returns all alive stacks from particular side excluding turrets
|
||||
TStacks battleAliveStacks(ui8 side) const;
|
||||
const CStack * battleGetStackByID(int ID, bool onlyAlive = true) const; //returns stack info by given ID
|
||||
bool battleIsObstacleVisibleForSide(const CObstacleInstance & coi, BattlePerspective::BattlePerspective side) const;
|
||||
@ -279,7 +293,7 @@ public:
|
||||
SpellID getRandomCastedSpell(const CStack * caster) const; //called at the beginning of turn for Faerie Dragon
|
||||
|
||||
//checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into acount general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem battleIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const;
|
||||
ESpellCastProblem::ESpellCastProblem battleStackIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, const CStack * subject) const;
|
||||
|
||||
|
||||
const CStack * getStackIf(std::function<bool(const CStack*)> pred) const;
|
||||
@ -307,6 +321,11 @@ public:
|
||||
AccessibilityInfo getAccesibility(const std::vector<BattleHex> &accessibleHexes) const; //given hexes will be marked as accessible
|
||||
std::pair<const CStack *, BattleHex> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const;
|
||||
protected:
|
||||
|
||||
//checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into acount general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem battleIsImmune(const CGHeroInstance * caster, const CSpell * spell, ECastingMode::ECastingMode mode, BattleHex dest) const;
|
||||
|
||||
|
||||
ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters ¶ms) const;
|
||||
ReachabilityInfo makeBFS(const AccessibilityInfo &accessibility, const ReachabilityInfo::Parameters ¶ms) const;
|
||||
ReachabilityInfo makeBFS(const CStack *stack) const; //uses default parameters -> stack position and owner's perspective
|
||||
|
736
lib/CGameInfoCallback.cpp
Normal file
736
lib/CGameInfoCallback.cpp
Normal file
@ -0,0 +1,736 @@
|
||||
/*
|
||||
* CGameInfoCallback.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 "CGameInfoCallback.h"
|
||||
|
||||
#include "CGameState.h" // PlayerState
|
||||
#include "CObjectHandler.h" // for CGObjectInstance
|
||||
#include "StartInfo.h" // for StartInfo
|
||||
#include "BattleState.h" // for BattleInfo
|
||||
#include "NetPacks.h" // for InfoWindow
|
||||
|
||||
//TODO make clean
|
||||
#define ERROR_VERBOSE_OR_NOT_RET_VAL_IF(cond, verbose, txt, retVal) do {if(cond){if(verbose)logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
|
||||
#define ERROR_RET_IF(cond, txt) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return;}} while(0)
|
||||
#define ERROR_RET_VAL_IF(cond, txt, retVal) do {if(cond){logGlobal->errorStream() << BOOST_CURRENT_FUNCTION << ": " << txt; return retVal;}} while(0)
|
||||
|
||||
PlayerColor CGameInfoCallback::getOwner(ObjectInstanceID heroID) const
|
||||
{
|
||||
const CGObjectInstance *obj = getObj(heroID);
|
||||
ERROR_RET_VAL_IF(!obj, "No such object!", PlayerColor::CANNOT_DETERMINE);
|
||||
return obj->tempOwner;
|
||||
}
|
||||
|
||||
int CGameInfoCallback::getResource(PlayerColor Player, Res::ERes which) const
|
||||
{
|
||||
const PlayerState *p = getPlayer(Player);
|
||||
ERROR_RET_VAL_IF(!p, "No player info!", -1);
|
||||
ERROR_RET_VAL_IF(p->resources.size() <= which || which < 0, "No such resource!", -1);
|
||||
return p->resources[which];
|
||||
}
|
||||
|
||||
const CGHeroInstance* CGameInfoCallback::getSelectedHero( PlayerColor Player ) const
|
||||
{
|
||||
const PlayerState *p = getPlayer(Player);
|
||||
ERROR_RET_VAL_IF(!p, "No player info!", nullptr);
|
||||
return getHero(p->currentSelection);
|
||||
}
|
||||
|
||||
const CGHeroInstance* CGameInfoCallback::getSelectedHero() const
|
||||
{
|
||||
return getSelectedHero(gs->currentPlayer);
|
||||
}
|
||||
|
||||
const PlayerSettings * CGameInfoCallback::getPlayerSettings(PlayerColor color) const
|
||||
{
|
||||
return &gs->scenarioOps->getIthPlayersSettings(color);
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isAllowed( int type, int id )
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case 0:
|
||||
return gs->map->allowedSpell[id];
|
||||
case 1:
|
||||
return gs->map->allowedArtifact[id];
|
||||
case 2:
|
||||
return gs->map->allowedAbilities[id];
|
||||
default:
|
||||
ERROR_RET_VAL_IF(1, "Wrong type!", false);
|
||||
}
|
||||
}
|
||||
|
||||
const PlayerState * CGameInfoCallback::getPlayer(PlayerColor color, bool verbose) const
|
||||
{
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!hasAccess(color), verbose, "Cannot access player " << color << "info!", nullptr);
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!vstd::contains(gs->players,color), verbose, "Cannot find player " << color << "info!", nullptr);
|
||||
return &gs->players[color];
|
||||
}
|
||||
|
||||
const CTown * CGameInfoCallback::getNativeTown(PlayerColor color) const
|
||||
{
|
||||
const PlayerSettings *ps = getPlayerSettings(color);
|
||||
ERROR_RET_VAL_IF(!ps, "There is no such player!", nullptr);
|
||||
return VLC->townh->factions[ps->castle]->town;
|
||||
}
|
||||
|
||||
const CGObjectInstance * CGameInfoCallback::getObjByQuestIdentifier(int identifier) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!vstd::contains(gs->map->questIdentifierToId, identifier), "There is no object with such quest identifier!", nullptr);
|
||||
return getObj(gs->map->questIdentifierToId[identifier]);
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
||||
const CGObjectInstance* CGameInfoCallback::getObj(ObjectInstanceID objid, bool verbose) const
|
||||
{
|
||||
si32 oid = objid.num;
|
||||
if(oid < 0 || oid >= gs->map->objects.size())
|
||||
{
|
||||
if(verbose)
|
||||
logGlobal->errorStream() << "Cannot get object with id " << oid;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CGObjectInstance *ret = gs->map->objects[oid];
|
||||
if(!ret)
|
||||
{
|
||||
if(verbose)
|
||||
logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object was removed.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if(!isVisible(ret, player))
|
||||
{
|
||||
if(verbose)
|
||||
logGlobal->errorStream() << "Cannot get object with id " << oid << ". Object is not visible.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const CGHeroInstance* CGameInfoCallback::getHero(ObjectInstanceID objid) const
|
||||
{
|
||||
const CGObjectInstance *obj = getObj(objid, false);
|
||||
if(obj)
|
||||
return dynamic_cast<const CGHeroInstance*>(obj);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
const CGTownInstance* CGameInfoCallback::getTown(ObjectInstanceID objid) const
|
||||
{
|
||||
const CGObjectInstance *obj = getObj(objid, false);
|
||||
if(obj)
|
||||
return dynamic_cast<const CGTownInstance*>(obj);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CGameInfoCallback::getUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_IF(!canGetFullInfo(obj), "Cannot get info about not owned object!");
|
||||
ERROR_RET_IF(!obj->hasStackAtSlot(stackPos), "There is no such stack!");
|
||||
out = gs->getUpgradeInfo(obj->getStack(stackPos));
|
||||
//return gs->getUpgradeInfo(obj->getStack(stackPos));
|
||||
}
|
||||
|
||||
const StartInfo * CGameInfoCallback::getStartInfo(bool beforeRandomization /*= false*/) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
if(beforeRandomization)
|
||||
return gs->initialOpts;
|
||||
else
|
||||
return gs->scenarioOps;
|
||||
}
|
||||
|
||||
int CGameInfoCallback::getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_VAL_IF(!canGetFullInfo(caster), "Cannot get info about caster!", -1);
|
||||
//if there is a battle
|
||||
if(gs->curB)
|
||||
return gs->curB->battleGetSpellCost(sp, caster);
|
||||
|
||||
//if there is no battle
|
||||
return caster->getSpellCost(sp);
|
||||
}
|
||||
|
||||
int CGameInfoCallback::estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
|
||||
ERROR_RET_VAL_IF(hero && !canGetFullInfo(hero), "Cannot get info about caster!", -1);
|
||||
if(!gs->curB) //no battle
|
||||
{
|
||||
if (hero) //but we see hero's spellbook
|
||||
return gs->curB->calculateSpellDmg(
|
||||
sp, hero, nullptr, hero->getSpellSchoolLevel(sp), hero->getPrimSkillLevel(PrimarySkill::SPELL_POWER));
|
||||
else
|
||||
return 0; //mage guild
|
||||
}
|
||||
//gs->getHero(gs->currentPlayer)
|
||||
//const CGHeroInstance * ourHero = gs->curB->heroes[0]->tempOwner == player ? gs->curB->heroes[0] : gs->curB->heroes[1];
|
||||
const CGHeroInstance * ourHero = hero;
|
||||
return gs->curB->calculateSpellDmg(
|
||||
sp, ourHero, nullptr, ourHero->getSpellSchoolLevel(sp), ourHero->getPrimSkillLevel(PrimarySkill::SPELL_POWER));
|
||||
}
|
||||
|
||||
void CGameInfoCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj)
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_IF(!obj, "No guild object!");
|
||||
ERROR_RET_IF(obj->ID == Obj::TOWN && !canGetFullInfo(obj), "Cannot get info about town guild object!");
|
||||
//TODO: advmap object -> check if they're visited by our hero
|
||||
|
||||
if(obj->ID == Obj::TOWN || obj->ID == Obj::TAVERN)
|
||||
{
|
||||
gs->obtainPlayersStats(thi, gs->players[obj->tempOwner].towns.size());
|
||||
}
|
||||
else if(obj->ID == Obj::DEN_OF_THIEVES)
|
||||
{
|
||||
gs->obtainPlayersStats(thi, 20);
|
||||
}
|
||||
}
|
||||
|
||||
int CGameInfoCallback::howManyTowns(PlayerColor Player) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!hasAccess(Player), "Access forbidden!", -1);
|
||||
return gs->players[Player].towns.size();
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::getTownInfo( const CGObjectInstance *town, InfoAboutTown &dest ) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!isVisible(town, player), "Town is not visible!", false); //it's not a town or it's not visible for layer
|
||||
bool detailed = hasAccess(town->tempOwner);
|
||||
|
||||
//TODO vision support
|
||||
if(town->ID == Obj::TOWN)
|
||||
dest.initFromTown(static_cast<const CGTownInstance *>(town), detailed);
|
||||
else if(town->ID == Obj::GARRISON || town->ID == Obj::GARRISON2)
|
||||
dest.initFromArmy(static_cast<const CArmedInstance *>(town), detailed);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int3 CGameInfoCallback::guardingCreaturePosition (int3 pos) const //FIXME: redundant?
|
||||
{
|
||||
ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", int3(-1,-1,-1));
|
||||
return gs->guardingCreaturePosition(pos);
|
||||
}
|
||||
|
||||
std::vector<const CGObjectInstance*> CGameInfoCallback::getGuardingCreatures (int3 pos) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!isVisible(pos), "Tile is not visible!", std::vector<const CGObjectInstance*>());
|
||||
std::vector<const CGObjectInstance*> ret;
|
||||
for(auto cr : gs->guardingCreatures(pos))
|
||||
{
|
||||
ret.push_back(cr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const
|
||||
{
|
||||
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(hero);
|
||||
|
||||
ERROR_RET_VAL_IF(!h, "That's not a hero!", false);
|
||||
ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false);
|
||||
|
||||
//TODO vision support
|
||||
dest.initFromHero(h, hasAccess(h->tempOwner));
|
||||
return true;
|
||||
}
|
||||
|
||||
int CGameInfoCallback::getDate(Date::EDateType mode) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return gs->getDate(mode);
|
||||
}
|
||||
std::vector < std::string > CGameInfoCallback::getObjDescriptions(int3 pos) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
std::vector<std::string> ret;
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile given!", ret);
|
||||
|
||||
|
||||
for(const CGObjectInstance * obj : t->blockingObjects)
|
||||
ret.push_back(obj->getHoverText());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isVisible(int3 pos, boost::optional<PlayerColor> Player) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return gs->map->isInTheMap(pos) && (!Player || gs->isVisible(pos, *Player));
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isVisible(int3 pos) const
|
||||
{
|
||||
return isVisible(pos, player);
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isVisible( const CGObjectInstance *obj, boost::optional<PlayerColor> Player ) const
|
||||
{
|
||||
return gs->isVisible(obj, Player);
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const
|
||||
{
|
||||
return isVisible(obj, player);
|
||||
}
|
||||
// const CCreatureSet* CInfoCallback::getGarrison(const CGObjectInstance *obj) const
|
||||
// {
|
||||
// //boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
// if()
|
||||
// const CArmedInstance *armi = dynamic_cast<const CArmedInstance*>(obj);
|
||||
// if(!armi)
|
||||
// return nullptr;
|
||||
// else
|
||||
// return armi;
|
||||
// }
|
||||
|
||||
std::vector < const CGObjectInstance * > CGameInfoCallback::getBlockingObjs( int3 pos ) const
|
||||
{
|
||||
std::vector<const CGObjectInstance *> ret;
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
|
||||
|
||||
for(const CGObjectInstance * obj : t->blockingObjects)
|
||||
ret.push_back(obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector <const CGObjectInstance * > CGameInfoCallback::getVisitableObjs(int3 pos, bool verbose /*= true*/) const
|
||||
{
|
||||
std::vector<const CGObjectInstance *> ret;
|
||||
const TerrainTile *t = getTile(pos, verbose);
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!t, verbose, pos << " is not visible!", ret);
|
||||
|
||||
for(const CGObjectInstance * obj : t->visitableObjects)
|
||||
{
|
||||
if(player < nullptr || obj->ID != Obj::EVENT) //hide events from players
|
||||
ret.push_back(obj);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
const CGObjectInstance * CGameInfoCallback::getTopObj (int3 pos) const
|
||||
{
|
||||
return vstd::backOrNull(getVisitableObjs(pos));
|
||||
}
|
||||
|
||||
std::vector < const CGObjectInstance * > CGameInfoCallback::getFlaggableObjects(int3 pos) const
|
||||
{
|
||||
std::vector<const CGObjectInstance *> ret;
|
||||
const TerrainTile *t = getTile(pos);
|
||||
ERROR_RET_VAL_IF(!t, "Not a valid tile requested!", ret);
|
||||
for(const CGObjectInstance *obj : t->blockingObjects)
|
||||
if(obj->tempOwner != PlayerColor::UNFLAGGABLE)
|
||||
ret.push_back(obj);
|
||||
// const std::vector < std::pair<const CGObjectInstance*,SDL_Rect> > & objs = CGI->mh->ttiles[pos.x][pos.y][pos.z].objects;
|
||||
// for(size_t b=0; b<objs.size(); ++b)
|
||||
// {
|
||||
// if(objs[b].first->tempOwner!=254 && !((objs[b].first->defInfo->blockMap[pos.y - objs[b].first->pos.y + 5] >> (objs[b].first->pos.x - pos.x)) & 1))
|
||||
// ret.push_back(CGI->mh->ttiles[pos.x][pos.y][pos.z].objects[b].first);
|
||||
// }
|
||||
return ret;
|
||||
}
|
||||
|
||||
int3 CGameInfoCallback::getMapSize() const
|
||||
{
|
||||
return int3(gs->map->width, gs->map->height, gs->map->twoLevel ? 2 : 1);
|
||||
}
|
||||
|
||||
std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const
|
||||
{
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
std::vector<const CGHeroInstance *> ret;
|
||||
//ERROR_RET_VAL_IF(!isOwnedOrVisited(townOrTavern), "Town or tavern must be owned or visited!", ret);
|
||||
//TODO: town needs to be owned, advmap tavern needs to be visited; to be reimplemented when visit tracking is done
|
||||
range::copy(gs->players[*player].availableHeroes, std::back_inserter(ret));
|
||||
vstd::erase_if(ret, [](const CGHeroInstance *h) { return h == nullptr; });
|
||||
return ret;
|
||||
}
|
||||
|
||||
const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
|
||||
{
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!isVisible(tile), verbose, tile << " is not visible!", nullptr);
|
||||
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return &gs->map->getTile(tile);
|
||||
}
|
||||
|
||||
EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTownInstance *t, BuildingID ID )
|
||||
{
|
||||
ERROR_RET_VAL_IF(!canGetFullInfo(t), "Town is not owned!", EBuildingState::TOWN_NOT_OWNED);
|
||||
|
||||
if(!t->town->buildings.count(ID))
|
||||
return EBuildingState::BUILDING_ERROR;
|
||||
|
||||
const CBuilding * building = t->town->buildings.at(ID);
|
||||
|
||||
|
||||
if(t->hasBuilt(ID)) //already built
|
||||
return EBuildingState::ALREADY_PRESENT;
|
||||
|
||||
//can we build it?
|
||||
if(vstd::contains(t->forbiddenBuildings, ID))
|
||||
return EBuildingState::FORBIDDEN; //forbidden
|
||||
|
||||
if(ID == BuildingID::CAPITOL)
|
||||
{
|
||||
const PlayerState *ps = getPlayer(t->tempOwner);
|
||||
if(ps)
|
||||
{
|
||||
for(const CGTownInstance *t : ps->towns)
|
||||
{
|
||||
if(t->hasBuilt(BuildingID::CAPITOL))
|
||||
{
|
||||
return EBuildingState::HAVE_CAPITAL; //no more than one capitol
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ID == BuildingID::SHIPYARD)
|
||||
{
|
||||
const TerrainTile *tile = getTile(t->bestLocation(), false);
|
||||
|
||||
if(!tile || tile->terType != ETerrainType::WATER)
|
||||
return EBuildingState::NO_WATER; //lack of water
|
||||
}
|
||||
|
||||
auto buildTest = [&](const BuildingID & id)
|
||||
{
|
||||
return t->hasBuilt(id);
|
||||
};
|
||||
|
||||
if(t->builded >= VLC->modh->settings.MAX_BUILDING_PER_TURN)
|
||||
return EBuildingState::CANT_BUILD_TODAY; //building limit
|
||||
|
||||
if (!building->requirements.test(buildTest))
|
||||
return EBuildingState::PREREQUIRES;
|
||||
|
||||
if (building->upgrade != BuildingID::NONE && !t->hasBuilt(building->upgrade))
|
||||
return EBuildingState::MISSING_BASE;
|
||||
|
||||
//checking resources
|
||||
if(!building->resources.canBeAfforded(getPlayer(t->tempOwner)->resources))
|
||||
return EBuildingState::NO_RESOURCES; //lack of res
|
||||
|
||||
return EBuildingState::ALLOWED;
|
||||
}
|
||||
|
||||
const CMapHeader * CGameInfoCallback::getMapHeader() const
|
||||
{
|
||||
return gs->map;
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::hasAccess(boost::optional<PlayerColor> playerId) const
|
||||
{
|
||||
return !player || gs->getPlayerRelations( *playerId, *player ) != PlayerRelations::ENEMIES;
|
||||
}
|
||||
|
||||
EPlayerStatus::EStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const
|
||||
{
|
||||
const PlayerState *ps = gs->getPlayer(player, verbose);
|
||||
ERROR_VERBOSE_OR_NOT_RET_VAL_IF(!ps, verbose, "No such player!", EPlayerStatus::WRONG);
|
||||
|
||||
return ps->status;
|
||||
}
|
||||
|
||||
std::string CGameInfoCallback::getTavernGossip(const CGObjectInstance * townOrTavern) const
|
||||
{
|
||||
return "GOSSIP TEST";
|
||||
}
|
||||
|
||||
PlayerRelations::PlayerRelations CGameInfoCallback::getPlayerRelations( PlayerColor color1, PlayerColor color2 ) const
|
||||
{
|
||||
return gs->getPlayerRelations(color1, color2);
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::canGetFullInfo(const CGObjectInstance *obj) const
|
||||
{
|
||||
return !obj || hasAccess(obj->tempOwner);
|
||||
}
|
||||
|
||||
int CGameInfoCallback::getHeroCount( PlayerColor player, bool includeGarrisoned ) const
|
||||
{
|
||||
int ret = 0;
|
||||
const PlayerState *p = gs->getPlayer(player);
|
||||
ERROR_RET_VAL_IF(!p, "No such player!", -1);
|
||||
|
||||
if(includeGarrisoned)
|
||||
return p->heroes.size();
|
||||
else
|
||||
for(auto & elem : p->heroes)
|
||||
if(!elem->inTownGarrison)
|
||||
ret++;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isOwnedOrVisited(const CGObjectInstance *obj) const
|
||||
{
|
||||
if(canGetFullInfo(obj))
|
||||
return true;
|
||||
|
||||
const TerrainTile *t = getTile(obj->visitablePos()); //get entrance tile
|
||||
const CGObjectInstance *visitor = t->visitableObjects.back(); //visitong hero if present or the obejct itself at last
|
||||
return visitor->ID == Obj::HERO && canGetFullInfo(visitor); //owned or allied hero is a visitor
|
||||
}
|
||||
|
||||
PlayerColor CGameInfoCallback::getCurrentPlayer() const
|
||||
{
|
||||
return gs->currentPlayer;
|
||||
}
|
||||
|
||||
CGameInfoCallback::CGameInfoCallback()
|
||||
{
|
||||
}
|
||||
|
||||
CGameInfoCallback::CGameInfoCallback(CGameState *GS, boost::optional<PlayerColor> Player)
|
||||
{
|
||||
gs = GS;
|
||||
player = Player;
|
||||
}
|
||||
|
||||
const std::vector< std::vector< std::vector<ui8> > > & CPlayerSpecificInfoCallback::getVisibilityMap() const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
return gs->getPlayerTeam(*player)->fogOfWarMap;
|
||||
}
|
||||
|
||||
int CPlayerSpecificInfoCallback::howManyTowns() const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1);
|
||||
return CGameInfoCallback::howManyTowns(*player);
|
||||
}
|
||||
|
||||
std::vector < const CGTownInstance *> CPlayerSpecificInfoCallback::getTownsInfo(bool onlyOur) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
std::vector < const CGTownInstance *> ret = std::vector < const CGTownInstance *>();
|
||||
for(const auto & i : gs->players)
|
||||
{
|
||||
for(const auto & town : i.second.towns)
|
||||
{
|
||||
if (i.first==player || (isVisible(town, player) && !onlyOur))
|
||||
{
|
||||
ret.push_back(town);
|
||||
}
|
||||
}
|
||||
} // for ( std::map<int, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++)
|
||||
return ret;
|
||||
}
|
||||
std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo(bool onlyOur) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
std::vector < const CGHeroInstance *> ret;
|
||||
for(auto hero : gs->map->heroesOnMap)
|
||||
{
|
||||
if( !player || (hero->tempOwner == *player) ||
|
||||
(isVisible(hero->getPosition(false), player) && !onlyOur) )
|
||||
{
|
||||
ret.push_back(hero);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
boost::optional<PlayerColor> CPlayerSpecificInfoCallback::getMyColor() const
|
||||
{
|
||||
return player;
|
||||
}
|
||||
|
||||
int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned) const
|
||||
{
|
||||
if (hero->inTownGarrison && !includeGarrisoned)
|
||||
return -1;
|
||||
|
||||
size_t index = 0;
|
||||
auto & heroes = gs->players[*player].heroes;
|
||||
|
||||
for (auto & heroe : heroes)
|
||||
{
|
||||
if (includeGarrisoned || !(heroe)->inTownGarrison)
|
||||
index++;
|
||||
|
||||
if (heroe == hero)
|
||||
return index;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int3 CPlayerSpecificInfoCallback::getGrailPos( double &outKnownRatio )
|
||||
{
|
||||
if (!player || CGObelisk::obeliskCount == 0)
|
||||
{
|
||||
outKnownRatio = 0.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
outKnownRatio = static_cast<double>(CGObelisk::visited[gs->getPlayerTeam(*player)->id]) / CGObelisk::obeliskCount;
|
||||
}
|
||||
return gs->map->grailPos;
|
||||
}
|
||||
|
||||
std::vector < const CGObjectInstance * > CPlayerSpecificInfoCallback::getMyObjects() const
|
||||
{
|
||||
std::vector < const CGObjectInstance * > ret;
|
||||
for(const CGObjectInstance * obj : gs->map->objects)
|
||||
{
|
||||
if(obj && obj->tempOwner == player)
|
||||
ret.push_back(obj);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector < const CGDwelling * > CPlayerSpecificInfoCallback::getMyDwellings() const
|
||||
{
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
std::vector < const CGDwelling * > ret;
|
||||
for(CGDwelling * dw : gs->getPlayer(*player)->dwellings)
|
||||
{
|
||||
ret.push_back(dw);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector <QuestInfo> CPlayerSpecificInfoCallback::getMyQuests() const
|
||||
{
|
||||
std::vector <QuestInfo> ret;
|
||||
for (auto quest : gs->getPlayer(*player)->quests)
|
||||
{
|
||||
ret.push_back (quest);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CPlayerSpecificInfoCallback::howManyHeroes(bool includeGarrisoned) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1);
|
||||
return getHeroCount(*player,includeGarrisoned);
|
||||
}
|
||||
|
||||
const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId, bool includeGarrisoned) const
|
||||
{
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
const PlayerState *p = getPlayer(*player);
|
||||
ERROR_RET_VAL_IF(!p, "No player info", nullptr);
|
||||
|
||||
if (!includeGarrisoned)
|
||||
{
|
||||
for(ui32 i = 0; i < p->heroes.size() && i<=serialId; i++)
|
||||
if(p->heroes[i]->inTownGarrison)
|
||||
serialId++;
|
||||
}
|
||||
ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->heroes.size(), "No player info", nullptr);
|
||||
return p->heroes[serialId];
|
||||
}
|
||||
|
||||
const CGTownInstance* CPlayerSpecificInfoCallback::getTownBySerial(int serialId) const
|
||||
{
|
||||
ASSERT_IF_CALLED_WITH_PLAYER
|
||||
const PlayerState *p = getPlayer(*player);
|
||||
ERROR_RET_VAL_IF(!p, "No player info", nullptr);
|
||||
ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->towns.size(), "No player info", nullptr);
|
||||
return p->towns[serialId];
|
||||
}
|
||||
|
||||
int CPlayerSpecificInfoCallback::getResourceAmount(Res::ERes type) const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", -1);
|
||||
return getResource(*player, type);
|
||||
}
|
||||
|
||||
TResources CPlayerSpecificInfoCallback::getResourceAmount() const
|
||||
{
|
||||
//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
|
||||
ERROR_RET_VAL_IF(!player, "Applicable only for player callbacks", TResources());
|
||||
return gs->players[*player].resources;
|
||||
}
|
||||
|
||||
const TeamState * CGameInfoCallback::getTeam( TeamID teamID ) const
|
||||
{
|
||||
ERROR_RET_VAL_IF(!vstd::contains(gs->teams, teamID), "Cannot find info for team " << teamID, nullptr);
|
||||
const TeamState *ret = &gs->teams[teamID];
|
||||
ERROR_RET_VAL_IF(!!player && !vstd::contains(ret->players, *player), "Illegal attempt to access team data!", nullptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const TeamState * CGameInfoCallback::getPlayerTeam( PlayerColor color ) const
|
||||
{
|
||||
const PlayerState * ps = getPlayer(color);
|
||||
if (ps)
|
||||
return getTeam(ps->team);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CGHeroInstance* CGameInfoCallback::getHeroWithSubid( int subid ) const
|
||||
{
|
||||
for(const CGHeroInstance *h : gs->map->heroesOnMap)
|
||||
if(h->subID == subid)
|
||||
return h;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PlayerColor CGameInfoCallback::getLocalPlayer() const
|
||||
{
|
||||
return getCurrentPlayer();
|
||||
}
|
||||
|
||||
bool CGameInfoCallback::isInTheMap(const int3 &pos) const
|
||||
{
|
||||
return gs->map->isInTheMap(pos);
|
||||
}
|
||||
|
||||
const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const
|
||||
{
|
||||
return gs->map->artInstances[aid.num];
|
||||
}
|
||||
|
||||
const CGObjectInstance * CGameInfoCallback::getObjInstance( ObjectInstanceID oid ) const
|
||||
{
|
||||
return gs->map->objects[oid.num];
|
||||
}
|
||||
|
||||
void IGameEventRealizer::showInfoDialog( InfoWindow *iw )
|
||||
{
|
||||
commitPackage(iw);
|
||||
}
|
||||
|
||||
void IGameEventRealizer::showInfoDialog(const std::string &msg, PlayerColor player)
|
||||
{
|
||||
InfoWindow iw;
|
||||
iw.player = player;
|
||||
iw.text << msg;
|
||||
showInfoDialog(&iw);
|
||||
}
|
||||
|
||||
void IGameEventRealizer::setObjProperty(ObjectInstanceID objid, int prop, si64 val)
|
||||
{
|
||||
SetObjectProperty sob;
|
||||
sob.id = objid;
|
||||
sob.what = prop;
|
||||
sob.val = static_cast<ui32>(val);
|
||||
commitPackage(&sob);
|
||||
}
|
||||
|
148
lib/CGameInfoCallback.h
Normal file
148
lib/CGameInfoCallback.h
Normal file
@ -0,0 +1,148 @@
|
||||
#pragma once
|
||||
|
||||
#include "ResourceSet.h" // for Res::ERes
|
||||
#include "CBattleCallback.h" //for CCallbackBase
|
||||
|
||||
/*
|
||||
* CGameInfoCallback.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 CGObjectInstance;
|
||||
struct InfoWindow;
|
||||
struct PlayerSettings;
|
||||
struct CPackForClient;
|
||||
struct TerrainTile;
|
||||
struct PlayerState;
|
||||
class CTown;
|
||||
struct StartInfo;
|
||||
struct InfoAboutTown;
|
||||
struct UpgradeInfo;
|
||||
struct SThievesGuildInfo;
|
||||
class CGDwelling;
|
||||
class CMapHeader;
|
||||
struct TeamState;
|
||||
struct QuestInfo;
|
||||
class int3;
|
||||
|
||||
|
||||
class DLL_LINKAGE CGameInfoCallback : public virtual CCallbackBase
|
||||
{
|
||||
protected:
|
||||
CGameInfoCallback();
|
||||
CGameInfoCallback(CGameState *GS, boost::optional<PlayerColor> Player);
|
||||
bool hasAccess(boost::optional<PlayerColor> playerId) const;
|
||||
bool isVisible(int3 pos, boost::optional<PlayerColor> Player) const;
|
||||
bool isVisible(const CGObjectInstance *obj, boost::optional<PlayerColor> Player) const;
|
||||
bool isVisible(const CGObjectInstance *obj) const;
|
||||
|
||||
bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode
|
||||
bool isOwnedOrVisited(const CGObjectInstance *obj) const;
|
||||
|
||||
public:
|
||||
//various
|
||||
int getDate(Date::EDateType mode=Date::DAY)const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
|
||||
const StartInfo * getStartInfo(bool beforeRandomization = false)const;
|
||||
bool isAllowed(int type, int id); //type: 0 - spell; 1- artifact; 2 - secondary skill
|
||||
|
||||
//player
|
||||
const PlayerState * getPlayer(PlayerColor color, bool verbose = true) const;
|
||||
int getResource(PlayerColor Player, Res::ERes which) const;
|
||||
bool isVisible(int3 pos) const;
|
||||
PlayerRelations::PlayerRelations getPlayerRelations(PlayerColor color1, PlayerColor color2) const;
|
||||
void getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj); //get thieves' guild info obtainable while visiting given object
|
||||
EPlayerStatus::EStatus getPlayerStatus(PlayerColor player, bool verbose = true) const; //-1 if no such player
|
||||
PlayerColor getCurrentPlayer() const; //player that currently makes move // TODO synchronous turns
|
||||
virtual PlayerColor getLocalPlayer() const; //player that is currently owning given client (if not a client, then returns current player)
|
||||
const PlayerSettings * getPlayerSettings(PlayerColor color) const;
|
||||
|
||||
|
||||
//armed object
|
||||
void getUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out)const;
|
||||
|
||||
//hero
|
||||
const CGHeroInstance* getHero(ObjectInstanceID objid) const;
|
||||
const CGHeroInstance* getHeroWithSubid(int subid) const;
|
||||
int getHeroCount(PlayerColor player, bool includeGarrisoned) const;
|
||||
bool getHeroInfo(const CGObjectInstance *hero, InfoAboutHero &dest) const;
|
||||
int getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //when called during battle, takes into account creatures' spell cost reduction
|
||||
int estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg
|
||||
const CGHeroInstance* getSelectedHero(PlayerColor player) const; //nullptr if no hero is selected
|
||||
const CGHeroInstance* getSelectedHero() const; //of current (active) player
|
||||
const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const;
|
||||
const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const;
|
||||
|
||||
//objects
|
||||
const CGObjectInstance* getObj(ObjectInstanceID objid, bool verbose = true) const;
|
||||
std::vector <const CGObjectInstance * > getBlockingObjs(int3 pos)const;
|
||||
std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos, bool verbose = true)const;
|
||||
std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;
|
||||
const CGObjectInstance * getTopObj (int3 pos) const;
|
||||
std::vector <std::string > getObjDescriptions(int3 pos)const; //returns descriptions of objects at pos in order from the lowest to the highest
|
||||
PlayerColor getOwner(ObjectInstanceID heroID) const;
|
||||
const CGObjectInstance *getObjByQuestIdentifier(int identifier) const; //nullptr if object has been removed (eg. killed)
|
||||
|
||||
//map
|
||||
int3 guardingCreaturePosition (int3 pos) const;
|
||||
std::vector<const CGObjectInstance*> getGuardingCreatures (int3 pos) const;
|
||||
const CMapHeader * getMapHeader()const;
|
||||
int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map
|
||||
const TerrainTile * getTile(int3 tile, bool verbose = true) const;
|
||||
bool isInTheMap(const int3 &pos) const;
|
||||
|
||||
//town
|
||||
const CGTownInstance* getTown(ObjectInstanceID objid) const;
|
||||
int howManyTowns(PlayerColor Player) const;
|
||||
const CGTownInstance * getTownInfo(int val, bool mode)const; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial)
|
||||
std::vector<const CGHeroInstance *> getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited
|
||||
std::string getTavernGossip(const CGObjectInstance * townOrTavern) const;
|
||||
EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
|
||||
virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const;
|
||||
const CTown *getNativeTown(PlayerColor color) const;
|
||||
|
||||
//from gs
|
||||
const TeamState *getTeam(TeamID teamID) const;
|
||||
const TeamState *getPlayerTeam(PlayerColor color) const;
|
||||
EBuildingState::EBuildingState canBuildStructure(const CGTownInstance *t, BuildingID ID) const;// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CPlayerSpecificInfoCallback : public CGameInfoCallback
|
||||
{
|
||||
public:
|
||||
int howManyTowns() const;
|
||||
int howManyHeroes(bool includeGarrisoned = true) const;
|
||||
int3 getGrailPos(double &outKnownRatio);
|
||||
boost::optional<PlayerColor> getMyColor() const;
|
||||
|
||||
std::vector <const CGTownInstance *> getTownsInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
|
||||
int getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned=true) const;
|
||||
const CGTownInstance* getTownBySerial(int serialId) const; // serial id is [0, number of towns)
|
||||
const CGHeroInstance* getHeroBySerial(int serialId, bool includeGarrisoned=true) const; // serial id is [0, number of heroes)
|
||||
std::vector <const CGHeroInstance *> getHeroesInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
|
||||
std::vector <const CGDwelling *> getMyDwellings() const; //returns all dwellings that belong to player
|
||||
std::vector <const CGObjectInstance * > getMyObjects() const; //returns all objects flagged by belonging player
|
||||
std::vector <QuestInfo> getMyQuests() const;
|
||||
|
||||
int getResourceAmount(Res::ERes type) const;
|
||||
TResources getResourceAmount() const;
|
||||
const std::vector< std::vector< std::vector<ui8> > > & getVisibilityMap()const; //returns visibility map
|
||||
const PlayerSettings * getPlayerSettings(PlayerColor color) const;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IGameEventRealizer
|
||||
{
|
||||
public:
|
||||
virtual void commitPackage(CPackForClient *pack) = 0;
|
||||
|
||||
virtual void showInfoDialog(InfoWindow *iw);
|
||||
virtual void setObjProperty(ObjectInstanceID objid, int prop, si64 val);
|
||||
|
||||
|
||||
virtual void showInfoDialog(const std::string &msg, PlayerColor player);
|
||||
};
|
||||
|
@ -22,7 +22,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// we can't use shared libraries on Android so here's a hack
|
||||
extern "C" DLL_EXPORT void VCAI_GetAiName(char* name);
|
||||
extern "C" DLL_EXPORT void VCAI_GetNewAI(shared_ptr<CGlobalAI> &out);
|
||||
|
||||
extern "C" DLL_EXPORT void StupidAI_GetAiName(char* name);
|
||||
extern "C" DLL_EXPORT void StupidAI_GetNewBattleAI(shared_ptr<CGlobalAI> &out);
|
||||
|
||||
extern "C" DLL_EXPORT void BattleAI_GetAiName(char* name);
|
||||
extern "C" DLL_EXPORT void BattleAI_GetNewBattleAI(shared_ptr<CBattleGameInterface> &out);
|
||||
#endif
|
||||
|
||||
template<typename rett>
|
||||
shared_ptr<rett> createAny(std::string dllname, std::string methodName)
|
||||
@ -35,6 +45,21 @@ shared_ptr<rett> createAny(std::string dllname, std::string methodName)
|
||||
TGetAIFun getAI = nullptr;
|
||||
TGetNameFun getName = nullptr;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// this is awful but it seems using shared libraries on some devices is even worse
|
||||
if (dllname.find("libVCAI.so") != std::string::npos) {
|
||||
getName = (TGetNameFun)VCAI_GetAiName;
|
||||
getAI = (TGetAIFun)VCAI_GetNewAI;
|
||||
} else if (dllname.find("libStupidAI.so") != std::string::npos) {
|
||||
getName = (TGetNameFun)StupidAI_GetAiName;
|
||||
getAI = (TGetAIFun)StupidAI_GetNewBattleAI;
|
||||
} else if (dllname.find("libBattleAI.so") != std::string::npos) {
|
||||
getName = (TGetNameFun)BattleAI_GetAiName;
|
||||
getAI = (TGetAIFun)BattleAI_GetNewBattleAI;
|
||||
} else {
|
||||
throw std::runtime_error("Don't know what to do with " + dllname + " and method " + methodName);
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef _WIN32
|
||||
HINSTANCE dll = LoadLibraryA(dllname.c_str());
|
||||
@ -69,6 +94,8 @@ shared_ptr<rett> createAny(std::string dllname, std::string methodName)
|
||||
throw std::runtime_error("Cannot find method " + methodName);
|
||||
}
|
||||
|
||||
#endif // __ANDROID__
|
||||
|
||||
getName(temp);
|
||||
logGlobal->infoStream() << "Loaded " << temp;
|
||||
|
||||
|
@ -734,6 +734,8 @@ BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2],
|
||||
terrain = ETerrainType::SAND;
|
||||
|
||||
BFieldType terType = battleGetBattlefieldType(tile);
|
||||
if (heroes[0] && heroes[0]->boat && heroes[1] && heroes[1]->boat)
|
||||
terType = BFieldType::SHIP_TO_SHIP;
|
||||
return BattleInfo::setupBattle(tile, terrain, terType, armies, heroes, creatureBank, town);
|
||||
}
|
||||
|
||||
@ -808,8 +810,8 @@ void CGameState::initNewGame()
|
||||
CStopWatch sw;
|
||||
|
||||
// Gen map
|
||||
CMapGenerator mapGenerator;
|
||||
map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release();
|
||||
CMapGenerator mapGenerator(scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
|
||||
map = mapGenerator.generate().release();
|
||||
|
||||
// Update starting options
|
||||
for(int i = 0; i < map->players.size(); ++i)
|
||||
@ -1000,7 +1002,7 @@ void CGameState::initGrailPosition()
|
||||
&& !t.visitable
|
||||
&& t.terType != ETerrainType::WATER
|
||||
&& t.terType != ETerrainType::ROCK
|
||||
&& map->grailPos.dist2d(int3(i,j,k)) <= map->grailRadious)
|
||||
&& map->grailPos.dist2dSQ(int3(i, j, k)) <= (map->grailRadious * map->grailRadious))
|
||||
allowedPos.push_back(int3(i,j,k));
|
||||
}
|
||||
}
|
||||
@ -1236,21 +1238,6 @@ CGameState::CrossoverHeroesList CGameState::getCrossoverHeroesFromPreviousScenar
|
||||
}
|
||||
}
|
||||
|
||||
// Now we need to perform deep copies of all heroes
|
||||
// The lambda below replaces pointer to a hero with a pointer to its deep copy.
|
||||
auto replaceWithDeepCopy = [](CGHeroInstance *&hero)
|
||||
{
|
||||
// We cache map original hero => copy.
|
||||
// We may be called multiple times with the same hero and should return a single copy.
|
||||
static std::map<CGHeroInstance*, CGHeroInstance*> oldToCopy;
|
||||
if(!oldToCopy[hero])
|
||||
oldToCopy[hero] = CMemorySerializer::deepCopy(*hero).release();
|
||||
|
||||
hero = oldToCopy[hero];
|
||||
};
|
||||
range::for_each(crossoverHeroes.heroesFromAnyPreviousScenarios, replaceWithDeepCopy);
|
||||
range::for_each(crossoverHeroes.heroesFromPreviousScenario, replaceWithDeepCopy);
|
||||
|
||||
return crossoverHeroes;
|
||||
}
|
||||
|
||||
@ -1877,6 +1864,8 @@ void CGameState::initMapObjects()
|
||||
}
|
||||
}
|
||||
CGTeleport::postInit(); //pairing subterranean gates
|
||||
|
||||
map->calculateGuardingGreaturePositions(); //calculate once again when all the guards are placed and initialized
|
||||
}
|
||||
|
||||
void CGameState::initVisitingAndGarrisonedHeroes()
|
||||
@ -1923,8 +1912,7 @@ BFieldType CGameState::battleGetBattlefieldType(int3 tile)
|
||||
for(auto &obj : map->objects)
|
||||
{
|
||||
//look only for objects covering given tile
|
||||
if( !obj || obj->pos.z != tile.z
|
||||
|| !obj->coveringAt(tile.x - obj->pos.x, tile.y - obj->pos.y))
|
||||
if( !obj || obj->pos.z != tile.z || !obj->coveringAt(tile.x, tile.y))
|
||||
continue;
|
||||
|
||||
switch(obj->ID)
|
||||
@ -2775,7 +2763,7 @@ std::vector<CGameState::CampaignHeroReplacement> CGameState::generateCampaignHer
|
||||
{
|
||||
auto hero = *it;
|
||||
crossoverHeroes.removeHeroFromBothLists(hero);
|
||||
campaignHeroReplacements.push_back(CampaignHeroReplacement(hero, heroPlaceholder->id));
|
||||
campaignHeroReplacements.push_back(CampaignHeroReplacement(CMemorySerializer::deepCopy(*hero).release(), heroPlaceholder->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2810,7 +2798,8 @@ std::vector<CGameState::CampaignHeroReplacement> CGameState::generateCampaignHer
|
||||
auto heroPlaceholder = heroPlaceholders[i];
|
||||
if(crossoverHeroes.heroesFromPreviousScenario.size() > i)
|
||||
{
|
||||
campaignHeroReplacements.push_back(CampaignHeroReplacement(crossoverHeroes.heroesFromPreviousScenario[i], heroPlaceholder->id));
|
||||
auto hero = crossoverHeroes.heroesFromPreviousScenario[i];
|
||||
campaignHeroReplacements.push_back(CampaignHeroReplacement(CMemorySerializer::deepCopy(*hero).release(), heroPlaceholder->id));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3088,7 +3077,8 @@ void InfoAboutTown::initFromTown(const CGTownInstance *t, bool detailed)
|
||||
{
|
||||
//include details about hero
|
||||
details = new Details;
|
||||
details->goldIncome = t->dailyIncome();
|
||||
TResources income = t->dailyIncome();
|
||||
details->goldIncome = income[Res::GOLD];
|
||||
details->customRes = t->hasBuilt(BuildingID::RESOURCE_SILO);
|
||||
details->hallLevel = t->hallLevel();
|
||||
details->garrisonedHero = t->garrisonHero;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "ResourceSet.h"
|
||||
#include "int3.h"
|
||||
#include "CObjectHandler.h"
|
||||
#include "IGameCallback.h"
|
||||
#include "CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
@ -459,7 +458,7 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
|
||||
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects & rand;
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possibles, std::minstd_rand & distr) const //picks secondary skill out from given possibilities
|
||||
SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possibles, CRandomGenerator & rand) const //picks secondary skill out from given possibilities
|
||||
{
|
||||
int totalProb = 0;
|
||||
for(auto & possible : possibles)
|
||||
@ -32,14 +32,16 @@ SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possi
|
||||
}
|
||||
if (totalProb != 0) // may trigger if set contains only banned skills (0 probability)
|
||||
{
|
||||
int ran = distr()%totalProb;
|
||||
auto ran = rand.nextInt(totalProb - 1);
|
||||
for(auto & possible : possibles)
|
||||
{
|
||||
ran -= secSkillProbability[possible];
|
||||
if(ran<0)
|
||||
if(ran < 0)
|
||||
{
|
||||
return possible;
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME: select randomly? How H3 handles such rare situation?
|
||||
return *possibles.begin();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class CGameInfo;
|
||||
class CGHeroInstance;
|
||||
struct BattleHex;
|
||||
class JsonNode;
|
||||
class CRandomGenerator;
|
||||
|
||||
struct SSpecialtyInfo
|
||||
{ si32 type;
|
||||
@ -132,7 +133,7 @@ public:
|
||||
CHeroClass();
|
||||
|
||||
bool isMagicHero() const;
|
||||
SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles, std::minstd_rand & distr) const; //picks secondary skill out from given possibilities
|
||||
SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles, CRandomGenerator & rand) const; //picks secondary skill out from given possibilities
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ include_directories(${Boost_INCLUDE_DIRS} ${SDL_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}
|
||||
set(lib_SRCS
|
||||
StdInc.cpp
|
||||
IGameCallback.cpp
|
||||
CGameInfoCallback.cpp
|
||||
CGameState.cpp
|
||||
CObjectHandler.cpp
|
||||
Connection.cpp
|
||||
@ -70,6 +71,7 @@ set(lib_SRCS
|
||||
CObstacleInstance.cpp
|
||||
CObjectConstructor.cpp
|
||||
CObjectWithReward.cpp
|
||||
CRandomGenerator.cpp
|
||||
CSpellHandler.cpp
|
||||
CThreadHelper.cpp
|
||||
CTownHandler.cpp
|
||||
@ -93,7 +95,6 @@ set(lib_HEADERS
|
||||
CondSh.h
|
||||
ConstTransitivePtr.h
|
||||
CBonusTypeHandler.h
|
||||
CRandomGenerator.h
|
||||
CScriptingModule.h
|
||||
CStopWatch.h
|
||||
FunctionList.h
|
||||
|
@ -310,6 +310,12 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali
|
||||
ModInfo & modInfo = modData[modName];
|
||||
bool result = true;
|
||||
|
||||
auto performValidate = [&,this](JsonNode & data, const std::string & name){
|
||||
handler->beforeValidate(data);
|
||||
if (validate)
|
||||
result &= JsonUtils::validate(data, "vcmi:" + objectName, name);
|
||||
};
|
||||
|
||||
// apply patches
|
||||
if (!modInfo.patches.isNull())
|
||||
JsonUtils::merge(modInfo.modData, modInfo.patches);
|
||||
@ -327,8 +333,8 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali
|
||||
if (originalData.size() > index)
|
||||
{
|
||||
JsonUtils::merge(originalData[index], data);
|
||||
if (validate)
|
||||
result &= JsonUtils::validate(originalData[index], "vcmi:" + objectName, name);
|
||||
|
||||
performValidate(originalData[index],name);
|
||||
handler->loadObject(modName, name, originalData[index], index);
|
||||
|
||||
originalData[index].clear(); // do not use same data twice (same ID)
|
||||
@ -337,8 +343,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali
|
||||
}
|
||||
}
|
||||
// normal new object or one with index bigger that data size
|
||||
if (validate)
|
||||
result &= JsonUtils::validate(data, "vcmi:" + objectName, name);
|
||||
performValidate(data,name);
|
||||
handler->loadObject(modName, name, data);
|
||||
}
|
||||
return result;
|
||||
@ -524,14 +529,14 @@ void CModHandler::loadConfigFromFile (std::string name)
|
||||
{
|
||||
settings.data = JsonUtils::assembleFromFiles("config/" + name);
|
||||
const JsonNode & hardcodedFeatures = settings.data["hardcodedFeatures"];
|
||||
|
||||
settings.MAX_HEROES_AVAILABLE_PER_PLAYER = hardcodedFeatures["MAX_HEROES_AVAILABLE_PER_PLAYER"].Float();
|
||||
settings.MAX_HEROES_ON_MAP_PER_PLAYER = hardcodedFeatures["MAX_HEROES_ON_MAP_PER_PLAYER"].Float();
|
||||
settings.CREEP_SIZE = hardcodedFeatures["CREEP_SIZE"].Float();
|
||||
settings.WEEKLY_GROWTH = hardcodedFeatures["WEEKLY_GROWTH_PERCENT"].Float();
|
||||
settings.NEUTRAL_STACK_EXP = hardcodedFeatures["NEUTRAL_STACK_EXP_DAILY"].Float();
|
||||
settings.MAX_BUILDING_PER_TURN = hardcodedFeatures["MAX_BUILDING_PER_TURN"].Float();
|
||||
settings.DWELLINGS_ACCUMULATE_CREATURES = hardcodedFeatures["DWELLINGS_ACCUMULATE_CREATURES"].Bool();
|
||||
settings.ALL_CREATURES_GET_DOUBLE_MONTHS = hardcodedFeatures["ALL_CREATURES_GET_DOUBLE_MONTHS"].Bool();
|
||||
|
||||
const JsonNode & gameModules = settings.data["modules"];
|
||||
modules.STACK_EXP = gameModules["STACK_EXPERIENCE"].Bool();
|
||||
modules.STACK_ARTIFACT = gameModules["STACK_ARTIFACTS"].Bool();
|
||||
|
@ -245,11 +245,13 @@ public:
|
||||
int MAX_BUILDING_PER_TURN;
|
||||
bool DWELLINGS_ACCUMULATE_CREATURES;
|
||||
bool ALL_CREATURES_GET_DOUBLE_MONTHS;
|
||||
int MAX_HEROES_AVAILABLE_PER_PLAYER;
|
||||
int MAX_HEROES_ON_MAP_PER_PLAYER;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & data & CREEP_SIZE & WEEKLY_GROWTH & NEUTRAL_STACK_EXP & MAX_BUILDING_PER_TURN;
|
||||
h & DWELLINGS_ACCUMULATE_CREATURES & ALL_CREATURES_GET_DOUBLE_MONTHS;
|
||||
h & DWELLINGS_ACCUMULATE_CREATURES & ALL_CREATURES_GET_DOUBLE_MONTHS & MAX_HEROES_AVAILABLE_PER_PLAYER & MAX_HEROES_ON_MAP_PER_PLAYER;
|
||||
}
|
||||
} settings;
|
||||
|
||||
|
@ -350,6 +350,21 @@ std::set<int3> CGObjectInstance::getBlockedPos() const
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::set<int3> CGObjectInstance::getBlockedOffsets() const
|
||||
{
|
||||
std::set<int3> ret;
|
||||
for(int w=0; w<getWidth(); ++w)
|
||||
{
|
||||
for(int h=0; h<getHeight(); ++h)
|
||||
{
|
||||
if (appearance.isBlockedAt(w, h))
|
||||
ret.insert(int3(-w, -h, 0));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const //screen printing priority comparing
|
||||
{
|
||||
if (appearance.printPriority != cmp.appearance.printPriority)
|
||||
@ -789,17 +804,14 @@ void CGHeroInstance::initHero()
|
||||
}
|
||||
assert(validTypes());
|
||||
|
||||
if (exp == 0xffffffff)
|
||||
level = 1;
|
||||
if(exp == 0xffffffff)
|
||||
{
|
||||
initExp();
|
||||
}
|
||||
else if (ID != Obj::PRISON)
|
||||
else
|
||||
{
|
||||
level = VLC->heroh->level(exp);
|
||||
}
|
||||
else //warp hero at the beginning of next turn
|
||||
{
|
||||
level = 1;
|
||||
levelUpAutomatically();
|
||||
}
|
||||
|
||||
if (VLC->modh->modules.COMMANDERS && !commander)
|
||||
@ -901,7 +913,7 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
|
||||
{
|
||||
int txt_id;
|
||||
|
||||
if(cb->getHeroCount(h->tempOwner,false) < GameConstants::MAX_HEROES_PER_PLAYER) //free hero slot
|
||||
if (cb->getHeroCount(h->tempOwner, false) < VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)//GameConstants::MAX_HEROES_PER_PLAYER) //free hero slot
|
||||
{
|
||||
cb->changeObjPos(id,pos+int3(1,0,0),0);
|
||||
//update hero parameters
|
||||
@ -975,7 +987,7 @@ void CGHeroInstance::initObj()
|
||||
if(!type)
|
||||
initHero(); //TODO: set up everything for prison before specialties are configured
|
||||
|
||||
skillsInfo.distribution.seed(rand());
|
||||
skillsInfo.rand.setSeed(cb->gameState()->getRandomGenerator().nextInt());
|
||||
skillsInfo.resetMagicSchoolCounter();
|
||||
skillsInfo.resetWisdomCounter();
|
||||
|
||||
@ -1574,7 +1586,6 @@ EAlignment::EAlignment CGHeroInstance::getAlignment() const
|
||||
void CGHeroInstance::initExp()
|
||||
{
|
||||
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
|
||||
level = 1;
|
||||
}
|
||||
|
||||
std::string CGHeroInstance::nodeName() const
|
||||
@ -1652,7 +1663,7 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
|
||||
return ArtBearer::HERO;
|
||||
}
|
||||
|
||||
std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills() const
|
||||
{
|
||||
std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible
|
||||
if (!skillsInfo.wisdomCounter)
|
||||
@ -1665,11 +1676,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
std::vector<SecondarySkill> ss;
|
||||
ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC;
|
||||
|
||||
auto rng = [=](ui32 val) mutable -> ui32
|
||||
{
|
||||
return skillsInfo.distribution() % val; //must be determined
|
||||
};
|
||||
std::random_shuffle(ss.begin(), ss.end(), rng);
|
||||
std::shuffle(ss.begin(), ss.end(), skillsInfo.rand.getStdGenerator());
|
||||
|
||||
for (auto skill : ss)
|
||||
{
|
||||
@ -1713,12 +1720,12 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
}
|
||||
else if(none.size() && canLearnSkill()) //hero have free skill slot
|
||||
{
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //new skill
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //new skill
|
||||
none.erase(skills.back());
|
||||
}
|
||||
else if(!basicAndAdv.empty())
|
||||
{
|
||||
skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.distribution)); //upgrade existing
|
||||
skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand)); //upgrade existing
|
||||
basicAndAdv.erase(skills.back());
|
||||
}
|
||||
|
||||
@ -1728,7 +1735,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
//3) give any other new skill
|
||||
if(!basicAndAdv.empty())
|
||||
{
|
||||
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.distribution);//upgrade existing
|
||||
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand);//upgrade existing
|
||||
skills.push_back(s);
|
||||
basicAndAdv.erase(s);
|
||||
}
|
||||
@ -1738,18 +1745,147 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
|
||||
}
|
||||
else if(none.size() && canLearnSkill())
|
||||
{
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //give new skill
|
||||
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //give new skill
|
||||
none.erase(skills.back());
|
||||
}
|
||||
|
||||
return skills;
|
||||
}
|
||||
|
||||
PrimarySkill::PrimarySkill CGHeroInstance::nextPrimarySkill() const
|
||||
{
|
||||
assert(gainsLevel());
|
||||
int randomValue = cb->gameState()->getRandomGenerator().nextInt(99), pom = 0, primarySkill = 0;
|
||||
const auto & skillChances = (level > 9) ? type->heroClass->primarySkillLowLevel : type->heroClass->primarySkillHighLevel;
|
||||
|
||||
for(; primarySkill < GameConstants::PRIMARY_SKILLS; ++primarySkill)
|
||||
{
|
||||
pom += skillChances[primarySkill];
|
||||
if(randomValue < pom)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
logGlobal->traceStream() << "The hero gets the primary skill " << primarySkill << " with a probability of " << randomValue << "%.";
|
||||
return static_cast<PrimarySkill::PrimarySkill>(primarySkill);
|
||||
}
|
||||
|
||||
boost::optional<SecondarySkill> CGHeroInstance::nextSecondarySkill() const
|
||||
{
|
||||
assert(gainsLevel());
|
||||
|
||||
boost::optional<SecondarySkill> chosenSecondarySkill;
|
||||
const auto proposedSecondarySkills = getLevelUpProposedSecondarySkills();
|
||||
if(!proposedSecondarySkills.empty())
|
||||
{
|
||||
std::vector<SecondarySkill> learnedSecondarySkills;
|
||||
for(auto secondarySkill : proposedSecondarySkills)
|
||||
{
|
||||
if(getSecSkillLevel(secondarySkill) > 0)
|
||||
{
|
||||
learnedSecondarySkills.push_back(secondarySkill);
|
||||
}
|
||||
}
|
||||
|
||||
auto & rand = cb->gameState()->getRandomGenerator();
|
||||
if(learnedSecondarySkills.empty())
|
||||
{
|
||||
// there are only new skills to learn, so choose anyone of them
|
||||
chosenSecondarySkill = *RandomGeneratorUtil::nextItem(proposedSecondarySkills, rand);
|
||||
}
|
||||
else
|
||||
{
|
||||
// preferably upgrade a already learned secondary skill
|
||||
chosenSecondarySkill = *RandomGeneratorUtil::nextItem(learnedSecondarySkills, rand);
|
||||
}
|
||||
}
|
||||
return chosenSecondarySkill;
|
||||
}
|
||||
|
||||
void CGHeroInstance::setPrimarySkill(PrimarySkill::PrimarySkill primarySkill, si64 value, ui8 abs)
|
||||
{
|
||||
if(primarySkill < PrimarySkill::EXPERIENCE)
|
||||
{
|
||||
Bonus * skill = getBonusLocalFirst(Selector::type(Bonus::PRIMARY_SKILL)
|
||||
.And(Selector::subtype(primarySkill))
|
||||
.And(Selector::sourceType(Bonus::HERO_BASE_SKILL)));
|
||||
assert(skill);
|
||||
|
||||
if(abs)
|
||||
{
|
||||
skill->val = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
skill->val += value;
|
||||
}
|
||||
}
|
||||
else if(primarySkill == PrimarySkill::EXPERIENCE)
|
||||
{
|
||||
if(abs)
|
||||
{
|
||||
exp = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
exp += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CGHeroInstance::gainsLevel() const
|
||||
{
|
||||
return exp >= VLC->heroh->reqExp(level+1);
|
||||
}
|
||||
|
||||
void CGHeroInstance::levelUp(std::vector<SecondarySkill> skills)
|
||||
{
|
||||
++level;
|
||||
|
||||
//deterministic secondary skills
|
||||
skillsInfo.magicSchoolCounter = (skillsInfo.magicSchoolCounter + 1) % maxlevelsToMagicSchool();
|
||||
skillsInfo.wisdomCounter = (skillsInfo.wisdomCounter + 1) % maxlevelsToWisdom();
|
||||
if(vstd::contains(skills, SecondarySkill::WISDOM))
|
||||
{
|
||||
skillsInfo.resetWisdomCounter();
|
||||
}
|
||||
|
||||
SecondarySkill spellSchools[] = {
|
||||
SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC};
|
||||
for(auto skill : spellSchools)
|
||||
{
|
||||
if(vstd::contains(skills, skill))
|
||||
{
|
||||
skillsInfo.resetMagicSchoolCounter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//specialty
|
||||
Updatespecialty();
|
||||
}
|
||||
|
||||
void CGHeroInstance::levelUpAutomatically()
|
||||
{
|
||||
while(gainsLevel())
|
||||
{
|
||||
const auto primarySkill = nextPrimarySkill();
|
||||
setPrimarySkill(primarySkill, 1, false);
|
||||
|
||||
auto proposedSecondarySkills = getLevelUpProposedSecondarySkills();
|
||||
|
||||
const auto secondarySkill = nextSecondarySkill();
|
||||
if(secondarySkill)
|
||||
{
|
||||
setSecSkillLevel(*secondarySkill, 1, false);
|
||||
}
|
||||
|
||||
//TODO why has the secondary skills to be passed to the method?
|
||||
levelUp(proposedSecondarySkills);
|
||||
}
|
||||
}
|
||||
|
||||
void CGDwelling::initObj()
|
||||
{
|
||||
switch(ID)
|
||||
@ -2080,6 +2216,7 @@ CGTownInstance::EFortLevel CGTownInstance::fortLevel() const //0 - none, 1 - for
|
||||
|
||||
int CGTownInstance::hallLevel() const // -1 - none, 0 - village, 1 - town, 2 - city, 3 - capitol
|
||||
{
|
||||
|
||||
if (hasBuilt(BuildingID::CAPITOL))
|
||||
return 3;
|
||||
if (hasBuilt(BuildingID::CITY_HALL))
|
||||
@ -2170,20 +2307,29 @@ GrowthInfo CGTownInstance::getGrowthInfo(int level) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CGTownInstance::dailyIncome() const
|
||||
TResources CGTownInstance::dailyIncome() const
|
||||
{
|
||||
int ret = 0;
|
||||
if (hasBuilt(BuildingID::GRAIL))
|
||||
ret+=5000;
|
||||
TResources ret;
|
||||
|
||||
for (auto & p : town->buildings)
|
||||
{
|
||||
BuildingID buildingUpgrade;
|
||||
|
||||
for (auto & p2 : town->buildings)
|
||||
{
|
||||
if (p2.second->upgrade == p.first)
|
||||
{
|
||||
buildingUpgrade = p2.first;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasBuilt(buildingUpgrade)&&(hasBuilt(p.first)))
|
||||
{
|
||||
ret += p.second->produce;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (hasBuilt(BuildingID::CAPITOL))
|
||||
ret+=4000;
|
||||
else if (hasBuilt(BuildingID::CITY_HALL))
|
||||
ret+=2000;
|
||||
else if (hasBuilt(BuildingID::TOWN_HALL))
|
||||
ret+=1000;
|
||||
else if (hasBuilt(BuildingID::VILLAGE_HALL))
|
||||
ret+=500;
|
||||
return ret;
|
||||
}
|
||||
bool CGTownInstance::hasFort() const
|
||||
@ -2325,13 +2471,15 @@ void CGTownInstance::newTurn() const
|
||||
{
|
||||
if (cb->getDate(Date::DAY_OF_WEEK) == 1) //reset on new week
|
||||
{
|
||||
auto & rand = cb->gameState()->getRandomGenerator();
|
||||
|
||||
//give resources for Rampart, Mystic Pond
|
||||
if (hasBuilt(BuildingID::MYSTIC_POND, ETownType::RAMPART)
|
||||
&& cb->getDate(Date::DAY) != 1 && (tempOwner < PlayerColor::PLAYER_LIMIT))
|
||||
{
|
||||
int resID = rand()%4+2;//bonus to random rare resource
|
||||
int resID = rand.nextInt(2, 5); //bonus to random rare resource
|
||||
resID = (resID==2)?1:resID;
|
||||
int resVal = rand()%4+1;//with size 1..4
|
||||
int resVal = rand.nextInt(1, 4);//with size 1..4
|
||||
cb->giveResource(tempOwner, static_cast<Res::ERes>(resID), resVal);
|
||||
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_FIRST, resID);
|
||||
cb->setObjProperty (id, ObjProperty::BONUS_VALUE_SECOND, resVal);
|
||||
@ -2356,11 +2504,11 @@ void CGTownInstance::newTurn() const
|
||||
}
|
||||
if (nativeCrits.size())
|
||||
{
|
||||
SlotID pos = nativeCrits[rand() % nativeCrits.size()];
|
||||
SlotID pos = *RandomGeneratorUtil::nextItem(nativeCrits, rand);
|
||||
StackLocation sl(this, pos);
|
||||
|
||||
const CCreature *c = getCreature(pos);
|
||||
if (rand()%100 < 90 || c->upgrades.empty()) //increase number if no upgrade available
|
||||
if (rand.nextInt(99) < 90 || c->upgrades.empty()) //increase number if no upgrade available
|
||||
{
|
||||
cb->changeStackCount(sl, c->growth);
|
||||
}
|
||||
@ -2369,9 +2517,9 @@ void CGTownInstance::newTurn() const
|
||||
cb->changeStackType(sl, VLC->creh->creatures[*c->upgrades.begin()]);
|
||||
}
|
||||
}
|
||||
if ((stacksCount() < GameConstants::ARMY_SIZE && rand()%100 < 25) || Slots().empty()) //add new stack
|
||||
if ((stacksCount() < GameConstants::ARMY_SIZE && rand.nextInt(99) < 25) || Slots().empty()) //add new stack
|
||||
{
|
||||
int i = rand() % std::min (GameConstants::CREATURES_PER_TOWN, cb->getDate(Date::MONTH)<<1);
|
||||
int i = rand.nextInt(std::min(GameConstants::CREATURES_PER_TOWN, cb->getDate(Date::MONTH) << 1) - 1);
|
||||
if (!town->creatures[i].empty())
|
||||
{
|
||||
CreatureID c = town->creatures[i][0];
|
||||
@ -3010,7 +3158,7 @@ void CGCreature::initObj()
|
||||
amount = 1;
|
||||
}
|
||||
}
|
||||
formation.randomFormation = rand();
|
||||
formation.randomFormation = cb->gameState()->getRandomGenerator().nextInt();
|
||||
|
||||
temppower = stacks[SlotID(0)]->count * 1000;
|
||||
refusedJoining = false;
|
||||
@ -3226,10 +3374,10 @@ void CGCreature::fight( const CGHeroInstance *h ) const
|
||||
if (formation.randomFormation % 100 < 50) //upgrade
|
||||
{
|
||||
SlotID slotId = SlotID(stacks.size() / 2);
|
||||
if(ui32 upgradesSize = getStack(slotId).type->upgrades.size())
|
||||
const auto & upgrades = getStack(slotId).type->upgrades;
|
||||
if(!upgrades.empty())
|
||||
{
|
||||
auto it = getStack(slotId).type->upgrades.cbegin(); //pick random in case there are more
|
||||
std::advance (it, rand() % upgradesSize);
|
||||
auto it = RandomGeneratorUtil::nextItem(upgrades, cb->gameState()->getRandomGenerator());
|
||||
cb->changeStackType(StackLocation(this, slotId), VLC->creh->creatures[*it]);
|
||||
}
|
||||
}
|
||||
@ -3520,17 +3668,28 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
||||
ObjectInstanceID destinationid;
|
||||
switch(ID)
|
||||
{
|
||||
case Obj::MONOLITH1: //one way - find corresponding exit monolith
|
||||
if(vstd::contains(objs,Obj::MONOLITH2) && vstd::contains(objs[Obj::MONOLITH2],subID) && objs[Obj::MONOLITH2][subID].size())
|
||||
destinationid = objs[Obj::MONOLITH2][subID][rand()%objs[Obj::MONOLITH2][subID].size()];
|
||||
case Obj::MONOLITH_ONE_WAY_ENTRANCE: //one way - find corresponding exit monolith
|
||||
{
|
||||
if(vstd::contains(objs,Obj::MONOLITH_ONE_WAY_EXIT) && vstd::contains(objs[Obj::MONOLITH_ONE_WAY_EXIT],subID) && objs[Obj::MONOLITH_ONE_WAY_EXIT][subID].size())
|
||||
{
|
||||
destinationid = *RandomGeneratorUtil::nextItem(objs[Obj::MONOLITH_ONE_WAY_EXIT][subID], cb->gameState()->getRandomGenerator());
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->warnStream() << "Cannot find corresponding exit monolith for "<< id;
|
||||
}
|
||||
break;
|
||||
case Obj::MONOLITH3://two way monolith - pick any other one
|
||||
}
|
||||
case Obj::MONOLITH_TWO_WAY://two way monolith - pick any other one
|
||||
case Obj::WHIRLPOOL: //Whirlpool
|
||||
if(vstd::contains(objs,ID) && vstd::contains(objs[ID],subID) && objs[ID][subID].size()>1)
|
||||
{
|
||||
while ((destinationid = objs[ID][subID][rand()%objs[ID][subID].size()]) == id); //choose another exit
|
||||
//choose another exit
|
||||
do
|
||||
{
|
||||
destinationid = *RandomGeneratorUtil::nextItem(objs[ID][subID], cb->gameState()->getRandomGenerator());
|
||||
} while(destinationid == id);
|
||||
|
||||
if (ID == Obj::WHIRLPOOL)
|
||||
{
|
||||
if (!h->hasBonusOfType(Bonus::WHIRLPOOL_PROTECTION))
|
||||
@ -3581,9 +3740,8 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
||||
if (ID == Obj::WHIRLPOOL)
|
||||
{
|
||||
std::set<int3> tiles = cb->getObj(destinationid)->getBlockedPos();
|
||||
auto it = tiles.begin();
|
||||
std::advance (it, rand() % tiles.size()); //picking random element of set is tiring
|
||||
cb->moveHero (h->id, *it + int3(1,0,0), true);
|
||||
auto & tile = *RandomGeneratorUtil::nextItem(tiles, cb->gameState()->getRandomGenerator());
|
||||
cb->moveHero(h->id, tile + int3(1,0,0), true);
|
||||
}
|
||||
else
|
||||
cb->moveHero (h->id,CGHeroInstance::convertPosition(cb->getObj(destinationid)->pos,true) - getVisitableOffset(), true);
|
||||
@ -3627,13 +3785,13 @@ void CGTeleport::postInit() //matches subterranean gates into pairs
|
||||
const CGObjectInstance *cur = gatesSplit[0][i];
|
||||
|
||||
//find nearest underground exit
|
||||
std::pair<int,double> best(-1,150000); //pair<pos_in_vector, distance>
|
||||
std::pair<int, si32> best(-1, std::numeric_limits<si32>::max()); //pair<pos_in_vector, distance^2>
|
||||
for(int j = 0; j < gatesSplit[1].size(); j++)
|
||||
{
|
||||
const CGObjectInstance *checked = gatesSplit[1][j];
|
||||
if(!checked)
|
||||
continue;
|
||||
double hlp = checked->pos.dist2d(cur->pos);
|
||||
si32 hlp = checked->pos.dist2dSQ(cur->pos);
|
||||
if(hlp < best.second)
|
||||
{
|
||||
best.first = j;
|
||||
@ -3647,10 +3805,8 @@ void CGTeleport::postInit() //matches subterranean gates into pairs
|
||||
gatesSplit[1][best.first] = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
gates.push_back(std::make_pair(cur->id, ObjectInstanceID()));
|
||||
}
|
||||
}
|
||||
objs.erase(Obj::SUBTERRANEAN_GATE);
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "int3.h"
|
||||
#include "GameConstants.h"
|
||||
#include "ResourceSet.h"
|
||||
#include "CRandomGenerator.h"
|
||||
|
||||
/*
|
||||
* CObjectHandler.h, part of VCMI engine
|
||||
@ -225,6 +226,7 @@ public:
|
||||
bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos)
|
||||
bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos)
|
||||
std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object
|
||||
std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object
|
||||
bool isVisitable() const; //returns true if object is visitable
|
||||
bool operator<(const CGObjectInstance & cmp) const; //screen printing priority comparing
|
||||
void hideTiles(PlayerColor ourplayer, int radius) const;
|
||||
@ -388,8 +390,8 @@ public:
|
||||
struct DLL_LINKAGE SecondarySkillsInfo
|
||||
{
|
||||
//skills are determined, initialized at map start
|
||||
//FIXME: remove mutable?
|
||||
mutable std::minstd_rand distribution;
|
||||
//FIXME remove mutable
|
||||
mutable CRandomGenerator rand;
|
||||
ui8 magicSchoolCounter;
|
||||
ui8 wisdomCounter;
|
||||
|
||||
@ -398,39 +400,10 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & magicSchoolCounter & wisdomCounter;
|
||||
if (h.saving)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << distribution;
|
||||
std::string str = stream.str();
|
||||
h & str;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string str;
|
||||
h & str;
|
||||
std::istringstream stream(str);
|
||||
stream >> distribution;
|
||||
}
|
||||
h & magicSchoolCounter & wisdomCounter & rand;
|
||||
}
|
||||
} skillsInfo;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
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 & visitedObjects;
|
||||
h & visitedTown & boat;
|
||||
h & type & specialty & commander;
|
||||
BONUS_TREE_DESERIALIZATION_FIX
|
||||
//visitied town pointer will be restored by map serialization method
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
int3 getSightCenter() const; //"center" tile from which the sight distance is calculated
|
||||
int getSightRadious() const; //sight distance (should be used if player-owned structure)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -452,9 +425,28 @@ public:
|
||||
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
|
||||
bool canLearnSkill() const; ///true if hero has free secondary skill slot
|
||||
void levelUp(std::vector<SecondarySkill> skills);
|
||||
|
||||
int maxMovePoints(bool onLand) const;
|
||||
int movementPointsAfterEmbark(int MPsBefore, int basicCost, bool disembark = false) const;
|
||||
@ -471,8 +463,6 @@ public:
|
||||
CStackBasicDescriptor calculateNecromancy (const BattleResult &battleResult) const;
|
||||
void showNecromancyDialog(const CStackBasicDescriptor &raisedStack) const;
|
||||
ECanDig diggingStatus() const; //0 - can dig; 1 - lack of movement; 2 -
|
||||
std::vector<SecondarySkill> levelUpProposedSkills() const;
|
||||
bool gainsLevel() const; //true if hero has lower level than should upon his experience
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -509,6 +499,22 @@ public:
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CSpecObjInfo
|
||||
@ -719,7 +725,7 @@ public:
|
||||
//checks if building is constructed and town has same subID
|
||||
bool hasBuilt(BuildingID buildingID) const;
|
||||
bool hasBuilt(BuildingID buildingID, int townID) const;
|
||||
int dailyIncome() const; //calculates daily income of this town
|
||||
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;
|
||||
|
86
lib/CRandomGenerator.cpp
Normal file
86
lib/CRandomGenerator.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
/*
|
||||
* CRandomGenerator.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 "CRandomGenerator.h"
|
||||
|
||||
boost::thread_specific_ptr<CRandomGenerator> CRandomGenerator::defaultRand;
|
||||
|
||||
CRandomGenerator::CRandomGenerator()
|
||||
{
|
||||
resetSeed();
|
||||
}
|
||||
|
||||
void CRandomGenerator::setSeed(int seed)
|
||||
{
|
||||
rand.seed(seed);
|
||||
}
|
||||
|
||||
void CRandomGenerator::resetSeed()
|
||||
{
|
||||
boost::hash<std::string> stringHash;
|
||||
auto threadIdHash = stringHash(boost::lexical_cast<std::string>(boost::this_thread::get_id()));
|
||||
setSeed(threadIdHash * std::time(nullptr));
|
||||
}
|
||||
|
||||
TRandI CRandomGenerator::getIntRange(int lower, int upper)
|
||||
{
|
||||
return boost::bind(TIntDist(lower, upper), boost::ref(rand));
|
||||
}
|
||||
|
||||
int CRandomGenerator::nextInt(int upper)
|
||||
{
|
||||
return getIntRange(0, upper)();
|
||||
}
|
||||
|
||||
int CRandomGenerator::nextInt(int lower, int upper)
|
||||
{
|
||||
return getIntRange(lower, upper)();
|
||||
}
|
||||
|
||||
int CRandomGenerator::nextInt()
|
||||
{
|
||||
return TIntDist()(rand);
|
||||
}
|
||||
|
||||
TRand CRandomGenerator::getDoubleRange(double lower, double upper)
|
||||
{
|
||||
return boost::bind(TRealDist(lower, upper), boost::ref(rand));
|
||||
}
|
||||
|
||||
double CRandomGenerator::nextDouble(double upper)
|
||||
{
|
||||
return getDoubleRange(0, upper)();
|
||||
}
|
||||
|
||||
double CRandomGenerator::nextDouble(double lower, double upper)
|
||||
{
|
||||
return getDoubleRange(lower, upper)();
|
||||
}
|
||||
|
||||
double CRandomGenerator::nextDouble()
|
||||
{
|
||||
return TRealDist()(rand);
|
||||
}
|
||||
|
||||
CRandomGenerator & CRandomGenerator::getDefault()
|
||||
{
|
||||
if(!defaultRand.get())
|
||||
{
|
||||
defaultRand.reset(new CRandomGenerator());
|
||||
}
|
||||
return *defaultRand.get();
|
||||
}
|
||||
|
||||
TGenerator & CRandomGenerator::getStdGenerator()
|
||||
{
|
||||
return rand;
|
||||
}
|
@ -19,82 +19,84 @@ typedef std::function<double()> TRand;
|
||||
|
||||
/// The random generator randomly generates integers and real numbers("doubles") between
|
||||
/// a given range. This is a header only class and mainly a wrapper for
|
||||
/// convenient usage of the standard random API.
|
||||
class CRandomGenerator : boost::noncopyable
|
||||
/// convenient usage of the standard random API. An instance of this RNG is not thread safe.
|
||||
class DLL_LINKAGE CRandomGenerator : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
/// Seeds the generator with the current time by default.
|
||||
CRandomGenerator()
|
||||
{
|
||||
rand.seed(static_cast<unsigned long>(std::time(nullptr)));
|
||||
}
|
||||
/// Seeds the generator by default with the product of the current time in milliseconds and the
|
||||
/// current thread ID.
|
||||
CRandomGenerator();
|
||||
|
||||
void setSeed(int seed)
|
||||
{
|
||||
rand.seed(seed);
|
||||
}
|
||||
void setSeed(int seed);
|
||||
|
||||
/// Resets the seed to the product of the current time in milliseconds and the
|
||||
/// current thread ID.
|
||||
void resetSeed();
|
||||
|
||||
/// Generate several integer numbers within the same range.
|
||||
/// e.g.: auto a = gen.getIntRange(0,10); a(); a(); a();
|
||||
/// requires: lower <= upper
|
||||
TRandI getIntRange(int lower, int upper)
|
||||
{
|
||||
return boost::bind(TIntDist(lower, upper), boost::ref(rand));
|
||||
}
|
||||
TRandI getIntRange(int lower, int upper);
|
||||
|
||||
/// Generates an integer between 0 and upper.
|
||||
/// requires: 0 <= upper
|
||||
int nextInt(int upper)
|
||||
{
|
||||
return getIntRange(0, upper)();
|
||||
}
|
||||
int nextInt(int upper);
|
||||
|
||||
/// requires: lower <= upper
|
||||
int nextInt(int lower, int upper)
|
||||
{
|
||||
return getIntRange(lower, upper)();
|
||||
}
|
||||
int nextInt(int lower, int upper);
|
||||
|
||||
/// Generates an integer between 0 and the maximum value it can hold.
|
||||
int nextInt()
|
||||
{
|
||||
return TIntDist()(rand);
|
||||
}
|
||||
int nextInt();
|
||||
|
||||
/// Generate several double/real numbers within the same range.
|
||||
/// e.g.: auto a = gen.getDoubleRange(4.5,10.2); a(); a(); a();
|
||||
/// requires: lower <= upper
|
||||
TRand getDoubleRange(double lower, double upper)
|
||||
{
|
||||
return boost::bind(TRealDist(lower, upper), boost::ref(rand));
|
||||
}
|
||||
TRand getDoubleRange(double lower, double upper);
|
||||
|
||||
/// Generates a double between 0 and upper.
|
||||
/// requires: 0 <= upper
|
||||
double nextDouble(double upper)
|
||||
{
|
||||
return getDoubleRange(0, upper)();
|
||||
}
|
||||
double nextDouble(double upper);
|
||||
|
||||
/// requires: lower <= upper
|
||||
double nextDouble(double lower, double upper)
|
||||
{
|
||||
return getDoubleRange(lower, upper)();
|
||||
}
|
||||
double nextDouble(double lower, double upper);
|
||||
|
||||
/// Generates a double between 0.0 and 1.0.
|
||||
double nextDouble()
|
||||
{
|
||||
return TRealDist()(rand);
|
||||
}
|
||||
double nextDouble();
|
||||
|
||||
/// Gets a globally accessible RNG which will be constructed once per thread. For the
|
||||
/// seed a combination of the thread ID and current time in milliseconds will be used.
|
||||
static CRandomGenerator & getDefault();
|
||||
|
||||
/// Provide method so that this RNG can be used with legacy std:: API
|
||||
TGenerator & getStdGenerator();
|
||||
|
||||
private:
|
||||
TGenerator rand;
|
||||
static boost::thread_specific_ptr<CRandomGenerator> defaultRand;
|
||||
|
||||
public:
|
||||
template <typename Handler>
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
if(h.saving)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << rand;
|
||||
std::string str = stream.str();
|
||||
h & str;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string str;
|
||||
h & str;
|
||||
std::istringstream stream(str);
|
||||
stream >> rand;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace RandomGeneratorUtil
|
||||
{
|
||||
/// Gets an iterator to an element of a nonempty container randomly. Undefined behaviour if container is empty.
|
||||
template<typename Container>
|
||||
auto nextItem(const Container & container, CRandomGenerator & rand) -> decltype(std::begin(container))
|
||||
{
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
|
||||
#include "IGameEventsReceiver.h"
|
||||
#include "IGameCallback.h"
|
||||
|
||||
/*
|
||||
* CScriptingModule.h, part of VCMI engine
|
||||
@ -14,6 +13,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
class IGameEventRealizer;
|
||||
class CPrivilagedInfoCallback;
|
||||
|
||||
class CScriptingModule : public IGameEventsReceiver, public IBattleEventsReceiver
|
||||
{
|
||||
public:
|
||||
@ -25,3 +27,4 @@ public:
|
||||
CScriptingModule(){}
|
||||
virtual ~CScriptingModule(){}
|
||||
};
|
||||
|
||||
|
@ -287,6 +287,7 @@ const CSpell::TargetInfo CSpell::getTargetInfo(const int level) const
|
||||
info.type = getTargetType();
|
||||
info.smart = levelInfo.smartTarget;
|
||||
info.massive = levelInfo.range == "X";
|
||||
info.onlyAlive = !isRisingSpell();
|
||||
|
||||
return info;
|
||||
}
|
||||
@ -317,6 +318,12 @@ bool CSpell::isNegative() const
|
||||
return positiveness == NEGATIVE;
|
||||
}
|
||||
|
||||
bool CSpell::isNeutral() const
|
||||
{
|
||||
return positiveness == NEUTRAL;
|
||||
}
|
||||
|
||||
|
||||
bool CSpell::isRisingSpell() const
|
||||
{
|
||||
return isRising;
|
||||
@ -406,15 +413,14 @@ void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
|
||||
bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
{
|
||||
//todo: use new bonus API
|
||||
//1. Check limiters
|
||||
for(auto b : limiters)
|
||||
//1. Check absolute limiters
|
||||
for(auto b : absoluteLimiters)
|
||||
{
|
||||
if (!obj->hasBonusOfType(b))
|
||||
return true;
|
||||
}
|
||||
|
||||
//2. Check absolute immunities
|
||||
//todo: check config: some creatures are unaffected always, for example undead to resurrection.
|
||||
for(auto b : absoluteImmunities)
|
||||
{
|
||||
if (obj->hasBonusOfType(b))
|
||||
@ -422,10 +428,19 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
}
|
||||
|
||||
//3. Check negation
|
||||
//FIXME: Orb of vulnerability mechanics is not such trivial
|
||||
if(obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES)) //Orb of vulnerability
|
||||
return false;
|
||||
|
||||
//4. Check negatable immunities
|
||||
//4. Check negatable limit
|
||||
for(auto b : limiters)
|
||||
{
|
||||
if (!obj->hasBonusOfType(b))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//5. Check negatable immunities
|
||||
for(auto b : immunities)
|
||||
{
|
||||
if (obj->hasBonusOfType(b))
|
||||
@ -444,7 +459,7 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
return false;
|
||||
};
|
||||
|
||||
//4. Check elemental immunities
|
||||
//6. Check elemental immunities
|
||||
if(fire)
|
||||
{
|
||||
if(battleTestElementalImmunity(Bonus::FIRE_IMMUNITY))
|
||||
@ -779,10 +794,9 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
|
||||
};
|
||||
|
||||
readBonusStruct("immunity", spell->immunities);
|
||||
|
||||
readBonusStruct("absoluteImmunity", spell->absoluteImmunities);
|
||||
|
||||
readBonusStruct("limit", spell->limiters);
|
||||
readBonusStruct("absoluteLimit", spell->absoluteLimiters);
|
||||
|
||||
|
||||
const JsonNode & graphicsNode = json["graphics"];
|
||||
@ -850,6 +864,23 @@ void CSpellHandler::afterLoadFinalization()
|
||||
bonus.sid = spell->id;
|
||||
}
|
||||
|
||||
void CSpellHandler::beforeValidate(JsonNode & object)
|
||||
{
|
||||
//handle "base" level info
|
||||
|
||||
JsonNode& levels = object["levels"];
|
||||
JsonNode& base = levels["base"];
|
||||
|
||||
auto inheritNode = [&](const std::string & name){
|
||||
JsonUtils::inherit(levels[name],base);
|
||||
};
|
||||
|
||||
inheritNode("none");
|
||||
inheritNode("basic");
|
||||
inheritNode("advanced");
|
||||
inheritNode("expert");
|
||||
|
||||
}
|
||||
|
||||
|
||||
CSpellHandler::~CSpellHandler()
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
ETargetType type;
|
||||
bool smart;
|
||||
bool massive;
|
||||
bool onlyAlive;
|
||||
};
|
||||
|
||||
SpellID id;
|
||||
@ -96,6 +97,7 @@ public:
|
||||
|
||||
bool isPositive() const;
|
||||
bool isNegative() const;
|
||||
bool isNeutral() const;
|
||||
|
||||
bool isRisingSpell() const;
|
||||
bool isDamageSpell() const;
|
||||
@ -136,9 +138,9 @@ public:
|
||||
& probabilities & attributes & combatSpell & creatureAbility & positiveness & counteredSpells & mainEffectAnim;
|
||||
h & isRising & isDamage & isOffensive;
|
||||
h & targetType;
|
||||
h & immunities & limiters;
|
||||
h & immunities & limiters & absoluteImmunities & absoluteLimiters;
|
||||
h & iconImmune;
|
||||
h & absoluteImmunities & defaultProbability;
|
||||
h & defaultProbability;
|
||||
|
||||
h & isSpecial;
|
||||
|
||||
@ -169,6 +171,7 @@ private:
|
||||
std::vector<Bonus::BonusType> immunities; //any of these grants immunity
|
||||
std::vector<Bonus::BonusType> absoluteImmunities; //any of these grants immunity, can't be negated
|
||||
std::vector<Bonus::BonusType> limiters; //all of them are required to be affected
|
||||
std::vector<Bonus::BonusType> absoluteLimiters; //all of them are required to be affected, can't be negated
|
||||
|
||||
///graphics related stuff
|
||||
|
||||
@ -202,6 +205,7 @@ public:
|
||||
|
||||
std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
|
||||
void afterLoadFinalization() override;
|
||||
void beforeValidate(JsonNode & object) override;
|
||||
|
||||
/**
|
||||
* Gets a list of default allowed spells. OH3 spells are all allowed by default.
|
||||
|
@ -105,9 +105,12 @@ JsonNode readBuilding(CLegacyConfigParser & parser)
|
||||
for(const std::string & resID : GameConstants::RESOURCE_NAMES)
|
||||
cost[resID].Float() = parser.readNumber();
|
||||
|
||||
|
||||
|
||||
cost.Struct().erase("mithril"); // erase mithril to avoid confusing validator
|
||||
|
||||
parser.endLine();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -303,6 +306,36 @@ void CTownHandler::loadBuilding(CTown &town, const std::string & stringID, const
|
||||
ret->name = source["name"].String();
|
||||
ret->description = source["description"].String();
|
||||
ret->resources = TResources(source["cost"]);
|
||||
ret->produce = TResources(source["produce"]);
|
||||
|
||||
//for compatibility with older town mods
|
||||
if(!ret->produce.nonZero())
|
||||
{
|
||||
if (ret->bid == BuildingID::VILLAGE_HALL) ret->produce[Res::GOLD] = 500;
|
||||
|
||||
if (ret->bid == BuildingID::TOWN_HALL) ret->produce[Res::GOLD] = 1000;
|
||||
|
||||
if (ret->bid == BuildingID::CITY_HALL) ret->produce[Res::GOLD] = 2000;
|
||||
|
||||
if (ret->bid == BuildingID::CAPITOL) ret->produce[Res::GOLD] = 4000;
|
||||
|
||||
if (ret->bid == BuildingID::GRAIL) ret->produce[Res::GOLD] = 5000;
|
||||
//
|
||||
if (ret->bid == BuildingID::RESOURCE_SILO)
|
||||
{
|
||||
if ((ret->town->primaryRes != Res::WOOD) && (ret->town->primaryRes != Res::ORE) && (ret->town->primaryRes != Res::GOLD))
|
||||
ret->produce[ret->town->primaryRes] = 1;
|
||||
else
|
||||
{
|
||||
if (ret->town->primaryRes == Res::GOLD) ret->produce[ret->town->primaryRes] = 500;
|
||||
else
|
||||
{
|
||||
ret->produce[Res::WOOD] = 1;
|
||||
ret->produce[Res::ORE] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadBuildingRequirements(town, *ret, source["requires"]);
|
||||
|
||||
@ -510,6 +543,17 @@ void CTownHandler::loadClientData(CTown &town, const JsonNode & source)
|
||||
info.guildWindow = source["guildWindow"].String();
|
||||
info.buildingsIcons = source["buildingsIcons"].String();
|
||||
|
||||
//left for back compatibility - will be removed later
|
||||
if (source["guildBackground"].String() != "")
|
||||
info.guildBackground = source["guildBackground"].String();
|
||||
else
|
||||
info.guildBackground = "TPMAGE.bmp";
|
||||
if (source["tavernVideo"].String() != "")
|
||||
info.tavernVideo = source["tavernVideo"].String();
|
||||
else
|
||||
info.tavernVideo = "TAVERN.BIK";
|
||||
//end of legacy assignment
|
||||
|
||||
info.advMapVillage = source["adventureMap"]["village"].String();
|
||||
info.advMapCastle = source["adventureMap"]["castle"].String();
|
||||
info.advMapCapitol = source["adventureMap"]["capitol"].String();
|
||||
@ -535,6 +579,8 @@ void CTownHandler::loadTown(CTown &town, const JsonNode & source)
|
||||
|
||||
town.moatDamage = source["moatDamage"].Float();
|
||||
|
||||
|
||||
|
||||
town.mageLevel = source["mageGuild"].Float();
|
||||
town.names = source["names"].convertTo<std::vector<std::string> >();
|
||||
|
||||
@ -648,6 +694,7 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, std::string identi
|
||||
faction->creatureBg120 = source["creatureBackground"]["120px"].String();
|
||||
faction->creatureBg130 = source["creatureBackground"]["130px"].String();
|
||||
|
||||
|
||||
faction->nativeTerrain = ETerrainType(vstd::find_pos(GameConstants::TERRAIN_NAMES,
|
||||
source["nativeTerrain"].String()));
|
||||
int alignment = vstd::find_pos(EAlignment::names, source["alignment"].String());
|
||||
@ -674,6 +721,7 @@ CFaction * CTownHandler::loadFromJson(const JsonNode &source, std::string identi
|
||||
void CTownHandler::loadObject(std::string scope, std::string name, const JsonNode & data)
|
||||
{
|
||||
auto object = loadFromJson(data, name);
|
||||
|
||||
object->index = factions.size();
|
||||
if (object->town)
|
||||
{
|
||||
@ -766,3 +814,13 @@ std::vector<bool> CTownHandler::getDefaultAllowed() const
|
||||
}
|
||||
return allowedFactions;
|
||||
}
|
||||
std::set<TFaction> CTownHandler::getAllowedFactions() const
|
||||
{
|
||||
std::set<TFaction> allowedFactions;
|
||||
auto allowed = getDefaultAllowed();
|
||||
for (size_t i=0; i<allowed.size(); i++)
|
||||
if (allowed[i])
|
||||
allowedFactions.insert(i);
|
||||
|
||||
return allowedFactions;
|
||||
}
|
||||
|
@ -25,6 +25,9 @@ class CFaction;
|
||||
/// a typical building encountered in every castle ;]
|
||||
/// this is structure available to both client and server
|
||||
/// contains all mechanics-related data about town structures
|
||||
|
||||
|
||||
|
||||
class DLL_LINKAGE CBuilding
|
||||
{
|
||||
|
||||
@ -36,6 +39,7 @@ public:
|
||||
|
||||
CTown * town; // town this building belongs to
|
||||
TResources resources;
|
||||
TResources produce;
|
||||
TRequired requirements;
|
||||
std::string identifier;
|
||||
|
||||
@ -61,7 +65,7 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & identifier & town & bid & resources & name & description & requirements & upgrade & mode;
|
||||
h & identifier & town & bid & resources & produce & name & description & requirements & upgrade & mode;
|
||||
}
|
||||
|
||||
friend class CTownHandler;
|
||||
@ -117,6 +121,8 @@ public:
|
||||
std::string creatureBg120;
|
||||
std::string creatureBg130;
|
||||
|
||||
|
||||
|
||||
std::vector<SPuzzleInfo> puzzleMap;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
@ -170,9 +176,10 @@ public:
|
||||
int icons[2][2];
|
||||
std::string iconSmall[2][2]; /// icon names used during loading
|
||||
std::string iconLarge[2][2];
|
||||
|
||||
std::string tavernVideo;
|
||||
std::string musicTheme;
|
||||
std::string townBackground;
|
||||
std::string guildBackground;
|
||||
std::string guildWindow;
|
||||
std::string buildingsIcons;
|
||||
std::string hallBackground;
|
||||
@ -193,7 +200,7 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & icons & iconSmall & iconLarge & musicTheme & townBackground & guildWindow & buildingsIcons & hallBackground;
|
||||
h & icons & iconSmall & iconLarge & tavernVideo & musicTheme & townBackground & guildBackground & guildWindow & buildingsIcons & hallBackground;
|
||||
h & advMapVillage & advMapCastle & advMapCapitol & hallSlots & structures;
|
||||
h & siegePrefix & siegePositions & siegeShooter;
|
||||
}
|
||||
@ -263,6 +270,7 @@ public:
|
||||
void afterLoadFinalization() override;
|
||||
|
||||
std::vector<bool> getDefaultAllowed() const override;
|
||||
std::set<TFaction> getAllowedFactions() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include "mapping/CCampaignHandler.h" //for CCampaignState
|
||||
#include "rmg/CMapGenerator.h" // for CMapGenOptions
|
||||
|
||||
const ui32 version = 748;
|
||||
const ui32 version = 749;
|
||||
const ui32 minSupportedVersion = version;
|
||||
|
||||
class CConnection;
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
namespace GameConstants
|
||||
{
|
||||
const std::string VCMI_VERSION = "VCMI 0.95";
|
||||
const std::string VCMI_VERSION = "VCMI 0.95b";
|
||||
|
||||
const int BFIELD_WIDTH = 17;
|
||||
const int BFIELD_HEIGHT = 11;
|
||||
@ -450,6 +450,17 @@ namespace EWallState
|
||||
};
|
||||
}
|
||||
|
||||
namespace ETileType
|
||||
{
|
||||
enum ETileType
|
||||
{
|
||||
FREE,
|
||||
POSSIBLE,
|
||||
BLOCKED,
|
||||
USED
|
||||
};
|
||||
}
|
||||
|
||||
class Obj
|
||||
{
|
||||
public:
|
||||
@ -496,9 +507,9 @@ public:
|
||||
LEAN_TO = 39,
|
||||
LIBRARY_OF_ENLIGHTENMENT = 41,
|
||||
LIGHTHOUSE = 42,
|
||||
MONOLITH1 = 43,
|
||||
MONOLITH2 = 44,
|
||||
MONOLITH3 = 45,
|
||||
MONOLITH_ONE_WAY_ENTRANCE = 43,
|
||||
MONOLITH_ONE_WAY_EXIT = 44,
|
||||
MONOLITH_TWO_WAY = 45,
|
||||
MAGIC_PLAINS1 = 46,
|
||||
SCHOOL_OF_MAGIC = 47,
|
||||
MAGIC_SPRING = 48,
|
||||
|
@ -1363,7 +1363,7 @@ int CCreatureTypeLimiter::limit(const BonusLimitationContext &context) const
|
||||
if(!c)
|
||||
return true;
|
||||
return c != creature && (!includeUpgrades || !creature->isMyUpgrade(c));
|
||||
//drop bonus if it's not our creature and (we dont check upgrades or its not our upgrade)
|
||||
//drop bonus if it's not our creature and (we don`t check upgrades or its not our upgrade)
|
||||
}
|
||||
|
||||
CCreatureTypeLimiter::CCreatureTypeLimiter(const CCreature &Creature, bool IncludeUpgrades /*= true*/)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user