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

Multiple minor fixes:

- fixed starting armies of some heroes, including Bron #1602
- (debian) added vcmi-dbg package with debug information
- proper randomization of hero secondary skills, fixes #1603
- second capitol will show up as disabled immediately #1604
- proper deserialization of boost::variant
- empty file will no longer crash JsonNode parser
- fixed some compiler warnings
This commit is contained in:
Ivan Savenko 2013-12-03 09:03:37 +00:00
parent ee1b0459e6
commit 3d3f93275d
13 changed files with 157 additions and 72 deletions

View File

@ -12,6 +12,21 @@
"specialties": "specialties":
[ [
{ "type":10, "val": 1, "subtype": 5, "info": 0 } { "type":10, "val": 1, "subtype": 5, "info": 0 }
],
"army" :
[
{
"min" : 10, "max" : 20,
"creature" : "gnoll"
},
{
"min" : 4, "max" : 7,
"creature" : "basilisk"
},
{
"min" : 2, "max" : 4,
"creature" : "serpentFly"
}
] ]
}, },
"drakon": "drakon":

View File

@ -170,12 +170,15 @@
"army" : "army" :
[ [
{ {
"min" : 10, "max" : 20,
"creature" : "troglodyte" "creature" : "troglodyte"
}, },
{ {
"min" : 4, "max" : 7,
"creature" : "harpy" "creature" : "harpy"
}, },
{ {
"min" : 2, "max" : 3,
"creature" : "evilEye" "creature" : "evilEye"
} }
] ]
@ -198,12 +201,15 @@
"army" : "army" :
[ [
{ {
"min" : 10, "max" : 20,
"creature" : "goblin" "creature" : "goblin"
}, },
{ {
"min" : 4, "max" : 7,
"creature" : "goblinWolfRider" "creature" : "goblinWolfRider"
}, },
{ {
"min" : 2, "max" : 3,
"creature" : "orc" "creature" : "orc"
} }
] ]
@ -228,12 +234,15 @@
"army" : "army" :
[ [
{ {
"min" : 10, "max" : 20,
"creature" : "imp" "creature" : "imp"
}, },
{ {
"min" : 4, "max" : 7,
"creature" : "hellHound" "creature" : "hellHound"
}, },
{ {
"min" : 2, "max" : 3,
"creature" : "hellHound" "creature" : "hellHound"
} }
] ]

6
debian/control vendored
View File

@ -17,3 +17,9 @@ Description: Rewrite of the Heroes of Might and Magic 3 engine
. .
In its current state it already supports maps of any sizes, higher In its current state it already supports maps of any sizes, higher
resolutions and extended engine limits. resolutions and extended engine limits.
Package: vcmi-dbg
Architecture: any
Section: debug
Depends: vcmi (= ${binary:Version}), ${misc:Depends}
Description: Debug symbols for vcmi package

8
debian/rules vendored
View File

@ -6,3 +6,11 @@
# override disabled by default rpath - we need to find libvcmi.so with it: # override disabled by default rpath - we need to find libvcmi.so with it:
override_dh_auto_configure: override_dh_auto_configure:
dh_auto_configure -- -DCMAKE_SKIP_RPATH=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBIN_DIR=games dh_auto_configure -- -DCMAKE_SKIP_RPATH=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBIN_DIR=games
.PHONY: override_dh_strip
override_dh_strip:
dh_strip --dbg-package=vcmi-dbg
override_dh_auto_install:
dh_auto_install --destdir=debian/vcmi
override_dh_installdocs:
dh_installdocs --link-doc=vcmi

View File

@ -2957,8 +2957,8 @@ DuelParameters DuelParameters::fromJSON(const std::string &fname)
else else
ss.heroId = -1; ss.heroId = -1;
for(const JsonNode &n : n["heroPrimSkills"].Vector()) for(const JsonNode &entry : n["heroPrimSkills"].Vector())
ss.heroPrimSkills.push_back(n.Float()); ss.heroPrimSkills.push_back(entry.Float());
for(const JsonNode &skillNode : n["heroSecSkills"].Vector()) for(const JsonNode &skillNode : n["heroSecSkills"].Vector())
{ {

View File

@ -22,7 +22,7 @@
* *
*/ */
SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possibles) const //picks secondary skill out from given possibilities SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possibles, std::minstd_rand & distr) const //picks secondary skill out from given possibilities
{ {
int totalProb = 0; int totalProb = 0;
for(auto & possible : possibles) for(auto & possible : possibles)
@ -31,7 +31,7 @@ SecondarySkill CHeroClass::chooseSecSkill(const std::set<SecondarySkill> & possi
} }
if (totalProb != 0) // may trigger if set contains only banned skills (0 probability) if (totalProb != 0) // may trigger if set contains only banned skills (0 probability)
{ {
int ran = rand()%totalProb; int ran = distr()%totalProb;
for(auto & possible : possibles) for(auto & possible : possibles)
{ {
ran -= secSkillProbability[possible]; ran -= secSkillProbability[possible];

View File

@ -121,7 +121,7 @@ public:
std::string imageMapFemale; std::string imageMapFemale;
bool isMagicHero() const; bool isMagicHero() const;
SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles) const; //picks secondary skill out from given possibilities SecondarySkill chooseSecSkill(const std::set<SecondarySkill> & possibles, std::minstd_rand & distr) const; //picks secondary skill out from given possibilities
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {

View File

@ -1016,7 +1016,7 @@ void CGHeroInstance::initObj()
if(!type) if(!type)
initHero(); //TODO: set up everything for prison before specialties are configured initHero(); //TODO: set up everything for prison before specialties are configured
skillsInfo.randomSeed = rand(); skillsInfo.distribution.seed(rand());
skillsInfo.resetMagicSchoolCounter(); skillsInfo.resetMagicSchoolCounter();
skillsInfo.resetWisdomCounter(); skillsInfo.resetWisdomCounter();
@ -1661,14 +1661,19 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
{ {
std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible std::vector<SecondarySkill> obligatorySkills; //hero is offered magic school or wisdom if possible
if (!skillsInfo.wisdomCounter)
{
if (cb->isAllowed(2, SecondarySkill::WISDOM) && !getSecSkillLevel(SecondarySkill::WISDOM))
obligatorySkills.push_back(SecondarySkill::WISDOM);
}
if (!skillsInfo.magicSchoolCounter) if (!skillsInfo.magicSchoolCounter)
{ {
std::vector<SecondarySkill> ss; std::vector<SecondarySkill> ss;
ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC, SecondarySkill::EARTH_MAGIC; ss += SecondarySkill::FIRE_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC, SecondarySkill::EARTH_MAGIC;
auto rng = [=](ui32 val)-> ui32 auto rng = [=](ui32 val) mutable -> ui32
{ {
return skillsInfo.randomSeed % val; //must be determined return skillsInfo.distribution() % val; //must be determined
}; };
std::random_shuffle(ss.begin(), ss.end(), rng); std::random_shuffle(ss.begin(), ss.end(), rng);
@ -1681,11 +1686,6 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
} }
} }
} }
if (!skillsInfo.wisdomCounter)
{
if (cb->isAllowed(2, SecondarySkill::WISDOM) && !getSecSkillLevel(SecondarySkill::WISDOM))
obligatorySkills.push_back(SecondarySkill::WISDOM);
}
std::vector<SecondarySkill> skills; std::vector<SecondarySkill> skills;
//picking sec. skills for choice //picking sec. skills for choice
@ -1696,7 +1696,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
for(auto & elem : secSkills) for(auto & elem : secSkills)
{ {
if(elem.second < 3) if(elem.second < SecSkillLevel::EXPERT)
basicAndAdv.insert(elem.first); basicAndAdv.insert(elem.first);
else else
expert.insert(elem.first); expert.insert(elem.first);
@ -1709,35 +1709,41 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
expert.erase (s); expert.erase (s);
} }
//first offered skill //first offered skill:
if (canLearnSkill() && obligatorySkills.size()) //offer always if possible // 1) give obligatory skill
// 2) give any other new skill
// 3) upgrade existing
if (canLearnSkill() && obligatorySkills.size() > 0)
{ {
skills.push_back (obligatorySkills[0]); skills.push_back (obligatorySkills[0]);
} }
else if(none.size() && canLearnSkill()) //hero have free skill slot
{
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //new skill
}
else if(!basicAndAdv.empty()) else if(!basicAndAdv.empty())
{ {
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv);//upgrade existing skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.distribution)); //upgrade existing
}
//second offered skill:
//1) upgrade existing
//2) give obligatory skill
//3) give any other new skill
if(!basicAndAdv.empty())
{
SecondarySkill s = type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.distribution);//upgrade existing
skills.push_back(s); skills.push_back(s);
basicAndAdv.erase(s); basicAndAdv.erase(s);
} }
else if(none.size() && canLearnSkill()) else if (canLearnSkill() && obligatorySkills.size() > 1)
{
skills.push_back(type->heroClass->chooseSecSkill(none)); //give new skill
none.erase(skills.back());
}
//second offered skill
if (canLearnSkill() && obligatorySkills.size() > 1)
{ {
skills.push_back (obligatorySkills[1]); skills.push_back (obligatorySkills[1]);
} }
else if(none.size() && canLearnSkill()) //hero have free skill slot else if(none.size() && canLearnSkill())
{ {
skills.push_back(type->heroClass->chooseSecSkill(none)); //new skill skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //give new skill
} none.erase(skills.back());
else if(!basicAndAdv.empty())
{
skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv)); //upgrade existing
} }
return skills; return skills;

View File

@ -350,7 +350,9 @@ public:
struct DLL_LINKAGE SecondarySkillsInfo struct DLL_LINKAGE SecondarySkillsInfo
{ {
ui32 randomSeed; //skills are determined, initialized at map start //skills are determined, initialized at map start
//FIXME: remove mutable?
mutable std::minstd_rand distribution;
ui8 magicSchoolCounter; ui8 magicSchoolCounter;
ui8 wisdomCounter; ui8 wisdomCounter;
@ -359,7 +361,21 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & randomSeed & magicSchoolCounter & wisdomCounter; 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;
}
} }
} skillsInfo; } skillsInfo;

View File

@ -19,6 +19,7 @@
#include <boost/mpl/equal_to.hpp> #include <boost/mpl/equal_to.hpp>
#include <boost/mpl/int.hpp> #include <boost/mpl/int.hpp>
#include <boost/mpl/identity.hpp> #include <boost/mpl/identity.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/any.hpp> #include <boost/any.hpp>
#include "ConstTransitivePtr.h" #include "ConstTransitivePtr.h"
@ -248,6 +249,30 @@ struct LoadWrong
} }
}; };
template<typename Variant, typename Source>
struct VariantLoaderHelper
{
Source & source;
std::vector<std::function<Variant()>> funcs;
VariantLoaderHelper(Source & source):
source(source)
{
mpl::for_each<typename Variant::types>(std::ref(*this));
}
template<typename Type>
void operator()(Type)
{
funcs.push_back([&]() -> Variant
{
Type obj;
source >> obj;
return Variant(obj);
});
}
};
template<typename T> template<typename T>
struct SerializationLevel struct SerializationLevel
{ {
@ -1179,27 +1204,20 @@ public:
data.resize(length); data.resize(length);
this->This()->read((void*)data.c_str(),length); this->This()->read((void*)data.c_str(),length);
} }
template <BOOST_VARIANT_ENUM_PARAMS(typename T)> template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
void loadSerializable(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data) void loadSerializable(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> &data)
{ {
typedef boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> TVariant;
VariantLoaderHelper<TVariant, CISer> loader(*this);
si32 which; si32 which;
*this >> which; *this >> which;
if(which == 0) assert(which < loader.funcs.size());
{ data = loader.funcs.at(which)();
T0 obj;
*this >> obj;
data = obj;
}
else if(which == 1)
{
T1 obj;
*this >> obj;
data = obj;
}
else
assert(0);
//TODO write more if needed, general solution would be much longer
} }
template <typename T> template <typename T>
void loadSerializable(boost::optional<T> & data) void loadSerializable(boost::optional<T> & data)
{ {

View File

@ -580,20 +580,6 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
if(vstd::contains(t->forbiddenBuildings, ID)) if(vstd::contains(t->forbiddenBuildings, ID))
return EBuildingState::FORBIDDEN; //forbidden return EBuildingState::FORBIDDEN; //forbidden
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;
if(ID == BuildingID::CAPITOL) if(ID == BuildingID::CAPITOL)
{ {
const PlayerState *ps = getPlayer(t->tempOwner); const PlayerState *ps = getPlayer(t->tempOwner);
@ -612,10 +598,24 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
{ {
const TerrainTile *tile = getTile(t->bestLocation(), false); const TerrainTile *tile = getTile(t->bestLocation(), false);
if(!tile || tile->terType != ETerrainType::WATER) if(!tile || tile->terType != ETerrainType::WATER)
return EBuildingState::NO_WATER; //lack of 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 //checking resources
if(!building->resources.canBeAfforded(getPlayer(t->tempOwner)->resources)) if(!building->resources.canBeAfforded(getPlayer(t->tempOwner)->resources))
return EBuildingState::NO_RESOURCES; //lack of res return EBuildingState::NO_RESOURCES; //lack of res

View File

@ -131,15 +131,22 @@ JsonNode JsonParser::parse(std::string fileName)
{ {
JsonNode root; JsonNode root;
if (!Unicode::isValidString(&input[0], input.size())) if (input.size() == 0)
error("Not a valid UTF-8 file", false); {
error("File is empty", false);
}
else
{
if (!Unicode::isValidString(&input[0], input.size()))
error("Not a valid UTF-8 file", false);
extractValue(root); extractValue(root);
extractWhitespace(false); extractWhitespace(false);
//Warn if there are any non-whitespace symbols left //Warn if there are any non-whitespace symbols left
if (pos < input.size()) if (pos < input.size())
error("Not all file was parsed!", true); error("Not all file was parsed!", true);
}
if (!errors.empty()) if (!errors.empty())
{ {

View File

@ -205,9 +205,9 @@ void CGameHandler::levelUpHero(const CGHeroInstance * hero)
else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically else if(hlu.skills.size() == 1 || hero->tempOwner == PlayerColor::NEUTRAL) //choose skill automatically
{ {
sendAndApply(&hlu); sendAndApply(&hlu);
auto rng = [&]()-> ui32 auto rng = [&]() mutable -> ui32
{ {
return hero->skillsInfo.randomSeed; //must be determined return hero->skillsInfo.distribution(); //must be determined
}; };
levelUpHero(hero, vstd::pickRandomElementOf (hlu.skills, rng)); levelUpHero(hero, vstd::pickRandomElementOf (hlu.skills, rng));
} }