1
0
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:
Ivan Savenko 2014-06-03 22:45:18 +03:00
commit 32b6568b65
143 changed files with 8788 additions and 8457 deletions

3
.gitignore vendored
View File

@ -5,3 +5,6 @@
*.a
*.res
*.layout
*.pro.user
*.pro.user.*
/CMakeLists.txt.user

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

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

View File

@ -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;
/*

View File

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

View File

@ -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()
{

View File

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

View File

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

View File

@ -1 +0,0 @@
See license.txt.

View File

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

View File

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

View File

@ -22,11 +22,6 @@
"config/wog/heroClasses.json"
],
"spells" :
[
"config/wog/spells.json"
],
"filesystem":
{
"" :

0
NEWS
View File

34
README
View File

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

View File

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

View File

@ -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())
{

View File

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

View File

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

View File

@ -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++)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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++)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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" ] },

View File

@ -338,7 +338,8 @@
"resurrects" :
{
"type" : "SPELLCASTER",
"subtype" : "spell.resurrection"
"subtype" : "spell.resurrection",
"val" : 3
},
"spellpoints" :
{

View File

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

View File

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

View File

@ -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" ] },

View File

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

View File

@ -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" ] },

View File

@ -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" ] },

View File

@ -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" ] },

View File

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

View File

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

View File

@ -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" ] },

View File

@ -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" ] },

View File

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

View File

@ -239,7 +239,7 @@
],
"specialties":
[
{ "type":2, "val": 5, "subtype": 11, "info": 1 }
{ "type":10, "val": 1, "subtype": 5, "info": 0 }
]
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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
}
}
}

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

File diff suppressed because it is too large Load Diff

2
debian/control vendored
View File

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

@ -1,2 +0,0 @@
NEWS
README

View File

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

View File

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

View File

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

View File

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

View File

@ -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 &params) const;
ReachabilityInfo makeBFS(const AccessibilityInfo &accessibility, const ReachabilityInfo::Parameters &params) const;
ReachabilityInfo makeBFS(const CStack *stack) const; //uses default parameters -> stack position and owner's perspective

736
lib/CGameInfoCallback.cpp Normal file
View 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
View 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);
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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