mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +02:00
@ -767,17 +767,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)
|
||||
@ -953,7 +950,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();
|
||||
|
||||
@ -1552,7 +1549,6 @@ EAlignment::EAlignment CGHeroInstance::getAlignment() const
|
||||
void CGHeroInstance::initExp()
|
||||
{
|
||||
exp = cb->gameState()->getRandomGenerator().nextInt(40, 89);
|
||||
level = 1;
|
||||
}
|
||||
|
||||
std::string CGHeroInstance::nodeName() const
|
||||
@ -1630,7 +1626,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)
|
||||
@ -1643,11 +1639,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)
|
||||
{
|
||||
@ -1691,12 +1683,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());
|
||||
}
|
||||
|
||||
@ -1706,7 +1698,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);
|
||||
}
|
||||
@ -1716,18 +1708,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)
|
||||
@ -2303,13 +2424,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);
|
||||
@ -2334,11 +2457,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);
|
||||
}
|
||||
@ -2347,9 +2470,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];
|
||||
@ -3316,7 +3439,7 @@ void CGCreature::initObj()
|
||||
amount = 1;
|
||||
}
|
||||
}
|
||||
formation.randomFormation = rand();
|
||||
formation.randomFormation = cb->gameState()->getRandomGenerator().nextInt();
|
||||
|
||||
temppower = stacks[SlotID(0)]->count * 1000;
|
||||
refusedJoining = false;
|
||||
@ -3532,10 +3655,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]);
|
||||
}
|
||||
}
|
||||
@ -3869,11 +3992,12 @@ void CGVisitableOPW::onHeroVisit( const CGHeroInstance * h ) const
|
||||
Component::EComponentType type = Component::RESOURCE;
|
||||
Res::ERes sub=Res::WOOD;
|
||||
int val=0;
|
||||
auto & rand = cb->gameState()->getRandomGenerator();
|
||||
|
||||
switch (ID)
|
||||
{
|
||||
case Obj::MYSTICAL_GARDEN:
|
||||
if (rand()%2)
|
||||
if(rand.nextInt(1) == 1)
|
||||
{
|
||||
sub = Res::GEMS;
|
||||
val = 5;
|
||||
@ -3886,8 +4010,8 @@ void CGVisitableOPW::onHeroVisit( const CGHeroInstance * h ) const
|
||||
break;
|
||||
case Obj::WINDMILL:
|
||||
mid = 170;
|
||||
sub = static_cast<Res::ERes>((rand() % 5) + 1);
|
||||
val = (rand() % 4) + 3;
|
||||
sub = static_cast<Res::ERes>(rand.nextInt(1, 5));
|
||||
val = rand.nextInt(3, 6);
|
||||
break;
|
||||
case Obj::WATER_WHEEL:
|
||||
mid = 164;
|
||||
@ -3923,16 +4047,27 @@ void CGTeleport::onHeroVisit( const CGHeroInstance * h ) const
|
||||
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()];
|
||||
{
|
||||
destinationid = *RandomGeneratorUtil::nextItem(objs[Obj::MONOLITH2][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::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))
|
||||
@ -3983,9 +4118,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);
|
||||
@ -5156,7 +5290,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
|
||||
messageID = 55;
|
||||
iw.soundID = soundBase::LUCK;
|
||||
gbonus.bonus.type = Bonus::LUCK;
|
||||
gbonus.bonus.val = rand()%5 - 1;
|
||||
gbonus.bonus.val = cb->gameState()->getRandomGenerator().nextInt(-1, 3);
|
||||
descr_id = 69;
|
||||
gbonus.bdescr.addReplacement((gbonus.bonus.val<0 ? "-" : "+") + boost::lexical_cast<std::string>(gbonus.bonus.val));
|
||||
break;
|
||||
|
Reference in New Issue
Block a user