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

View File

@ -170,12 +170,15 @@
"army" :
[
{
"min" : 10, "max" : 20,
"creature" : "troglodyte"
},
{
"min" : 4, "max" : 7,
"creature" : "harpy"
},
{
"min" : 2, "max" : 3,
"creature" : "evilEye"
}
]
@ -198,12 +201,15 @@
"army" :
[
{
"min" : 10, "max" : 20,
"creature" : "goblin"
},
{
"min" : 4, "max" : 7,
"creature" : "goblinWolfRider"
},
{
"min" : 2, "max" : 3,
"creature" : "orc"
}
]
@ -228,12 +234,15 @@
"army" :
[
{
"min" : 10, "max" : 20,
"creature" : "imp"
},
{
"min" : 4, "max" : 7,
"creature" : "hellHound"
},
{
"min" : 2, "max" : 3,
"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
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_dh_auto_configure:
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
ss.heroId = -1;
for(const JsonNode &n : n["heroPrimSkills"].Vector())
ss.heroPrimSkills.push_back(n.Float());
for(const JsonNode &entry : n["heroPrimSkills"].Vector())
ss.heroPrimSkills.push_back(entry.Float());
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;
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)
{
int ran = rand()%totalProb;
int ran = distr()%totalProb;
for(auto & possible : possibles)
{
ran -= secSkillProbability[possible];

View File

@ -121,7 +121,7 @@ public:
std::string imageMapFemale;
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)
{

View File

@ -1016,7 +1016,7 @@ void CGHeroInstance::initObj()
if(!type)
initHero(); //TODO: set up everything for prison before specialties are configured
skillsInfo.randomSeed = rand();
skillsInfo.distribution.seed(rand());
skillsInfo.resetMagicSchoolCounter();
skillsInfo.resetWisdomCounter();
@ -1661,14 +1661,19 @@ ArtBearer::ArtBearer CGHeroInstance::bearerType() const
std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
{
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)
{
std::vector<SecondarySkill> ss;
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);
@ -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;
//picking sec. skills for choice
@ -1696,7 +1696,7 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
for(auto & elem : secSkills)
{
if(elem.second < 3)
if(elem.second < SecSkillLevel::EXPERT)
basicAndAdv.insert(elem.first);
else
expert.insert(elem.first);
@ -1709,35 +1709,41 @@ std::vector<SecondarySkill> CGHeroInstance::levelUpProposedSkills() const
expert.erase (s);
}
//first offered skill
if (canLearnSkill() && obligatorySkills.size()) //offer always if possible
//first offered skill:
// 1) give obligatory skill
// 2) give any other new skill
// 3) upgrade existing
if (canLearnSkill() && obligatorySkills.size() > 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())
{
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);
basicAndAdv.erase(s);
}
else if(none.size() && canLearnSkill())
{
skills.push_back(type->heroClass->chooseSecSkill(none)); //give new skill
none.erase(skills.back());
}
//second offered skill
if (canLearnSkill() && obligatorySkills.size() > 1)
else if (canLearnSkill() && obligatorySkills.size() > 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
}
else if(!basicAndAdv.empty())
{
skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv)); //upgrade existing
skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.distribution)); //give new skill
none.erase(skills.back());
}
return skills;

View File

@ -350,7 +350,9 @@ public:
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 wisdomCounter;
@ -359,7 +361,21 @@ public:
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;

View File

@ -19,6 +19,7 @@
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/any.hpp>
#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>
struct SerializationLevel
{
@ -1179,27 +1204,20 @@ public:
data.resize(length);
this->This()->read((void*)data.c_str(),length);
}
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
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;
*this >> which;
if(which == 0)
{
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
assert(which < loader.funcs.size());
data = loader.funcs.at(which)();
}
template <typename T>
void loadSerializable(boost::optional<T> & data)
{

View File

@ -580,20 +580,6 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
if(vstd::contains(t->forbiddenBuildings, ID))
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)
{
const PlayerState *ps = getPlayer(t->tempOwner);
@ -612,10 +598,24 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
{
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
}
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

View File

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