Esempio n. 1
0
void CHeroHandler::loadHeroSkills(CHero * hero, const JsonNode & node)
{
	for(const JsonNode &set : node["skills"].Vector())
	{
		int skillLevel = boost::range::find(NSecondarySkill::levels, set["level"].String()) - std::begin(NSecondarySkill::levels);
		if (skillLevel < SecSkillLevel::LEVELS_SIZE)
		{
			size_t currentIndex = hero->secSkillsInit.size();
			hero->secSkillsInit.push_back(std::make_pair(SecondarySkill(-1), skillLevel));

			VLC->modh->identifiers.requestIdentifier("skill", set["skill"], [=](si32 id)
			{
				hero->secSkillsInit[currentIndex].first = SecondarySkill(id);
			});
		}
		else
		{
			logGlobal->errorStream() << "Unknown skill level: " <<set["level"].String();
		}
	}

	// spellbook is considered present if hero have "spellbook" entry even when this is an empty set (0 spells)
	hero->haveSpellBook = !node["spellbook"].isNull();

	for(const JsonNode & spell : node["spellbook"].Vector())
	{
		VLC->modh->identifiers.requestIdentifier("spell", spell,
		[=](si32 spellID)
		{
			hero->spells.insert(SpellID(spellID));
		});
	}
}
Esempio n. 2
0
void CGHeroInstance::recreateSecondarySkillsBonuses()
{
	auto secondarySkillsBonuses = getBonuses(Selector::sourceType(Bonus::SECONDARY_SKILL));
	for(auto bonus : *secondarySkillsBonuses)
		removeBonus(bonus);

	for(auto skill_info : secSkills)
		updateSkill(SecondarySkill(skill_info.first), skill_info.second);
}
Esempio n. 3
0
void CGSeerHut::completeQuest (const CGHeroInstance * h) const //reward
{
	switch (rewardType)
	{
		case EXPERIENCE:
		{
			TExpType expVal = h->calculateXp(rVal);
			cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false);
			break;
		}
		case MANA_POINTS:
		{
			cb->setManaPoints(h->id, h->mana+rVal);
			break;
		}
		case MORALE_BONUS: case LUCK_BONUS:
		{
			Bonus hb(Bonus::ONE_WEEK, (rewardType == 3 ? Bonus::MORALE : Bonus::LUCK),
				Bonus::OBJECT, rVal, h->id.getNum(), "", -1);
			GiveBonus gb;
			gb.id = h->id.getNum();
			gb.bonus = hb;
			cb->giveHeroBonus(&gb);
		}
			break;
		case RESOURCES:
			cb->giveResource(h->getOwner(), static_cast<Res::ERes>(rID), rVal);
			break;
		case PRIMARY_SKILL:
			cb->changePrimSkill(h, static_cast<PrimarySkill::PrimarySkill>(rID), rVal, false);
			break;
		case SECONDARY_SKILL:
			cb->changeSecSkill(h, SecondarySkill(rID), rVal, false);
			break;
		case ARTIFACT:
			cb->giveHeroNewArtifact(h, VLC->arth->artifacts[rID],ArtifactPosition::FIRST_AVAILABLE);
			break;
		case SPELL:
		{
			std::set<SpellID> spell;
			spell.insert (SpellID(rID));
			cb->changeSpells(h, true, spell);
		}
			break;
		case CREATURE:
			{
				CCreatureSet creatures;
				creatures.setCreature(SlotID(0), CreatureID(rID), rVal);
				cb->giveCreatures(this, h, creatures, false);
			}
			break;
		default:
			break;
	}
}
Esempio n. 4
0
bool TradeOnMarketplace::applyGh( CGameHandler *gh )
{
	//market must be owned or visited
	const IMarket *m = IMarket::castFrom(market);

	if(!m)
		COMPLAIN_AND_RETURN("market is not-a-market! :/");

	ui8 player = market->tempOwner;

	if(player >= GameConstants::PLAYER_LIMIT)
		player = gh->getTile(market->visitablePos())->visitableObjects.back()->tempOwner;

	if(player >= GameConstants::PLAYER_LIMIT)
		COMPLAIN_AND_RETURN("No player can use this market!");

	if(hero && (player != hero->tempOwner || hero->visitablePos() != market->visitablePos()))
		COMPLAIN_AND_RETURN("This hero can't use this marketplace!");

	ERROR_IF_NOT(player);

	switch(mode)
	{
	case EMarketMode::RESOURCE_RESOURCE:
		return gh->tradeResources(m, val, player, r1, r2);
	case EMarketMode::RESOURCE_PLAYER:
		return gh->sendResources(val, player, static_cast<Res::ERes>(r1), static_cast<TPlayerColor>(r2));
	case EMarketMode::CREATURE_RESOURCE:
		if(!hero)
			COMPLAIN_AND_RETURN("Only hero can sell creatures!");
		return gh->sellCreatures(val, m, hero, r1, static_cast<Res::ERes>(r2));
	case EMarketMode::RESOURCE_ARTIFACT:
		if(!hero)
			COMPLAIN_AND_RETURN("Only hero can buy artifacts!");
		return gh->buyArtifact(m, hero, static_cast<Res::ERes>(r1), ArtifactID(r2));
	case EMarketMode::ARTIFACT_RESOURCE:
		if(!hero)
			COMPLAIN_AND_RETURN("Only hero can sell artifacts!");
		return gh->sellArtifact(m, hero, ArtifactInstanceID(r1), static_cast<Res::ERes>(r2));
	case EMarketMode::CREATURE_UNDEAD:
		return gh->transformInUndead(m, hero, r1);
	case EMarketMode::RESOURCE_SKILL:
		return gh->buySecSkill(m, hero, SecondarySkill(r2));
	case EMarketMode::CREATURE_EXP:
		return gh->sacrificeCreatures(m, hero, r1, val);
	case EMarketMode::ARTIFACT_EXP:
		return gh->sacrificeArtifact(m, hero, ArtifactPosition(r1));
	default:
		COMPLAIN_AND_RETURN("Unknown exchange mode!");
	}
}
Esempio n. 5
0
void CGHeroInstance::initObj()
{
	blockVisit = true;
	auto  hs = new HeroSpecial();
	hs->setNodeType(CBonusSystemNode::SPECIALTY);
	attachTo(hs); //do we ever need to detach it?

	if(!type)
		initHero(); //TODO: set up everything for prison before specialties are configured

	skillsInfo.rand.setSeed(cb->gameState()->getRandomGenerator().nextInt());
	skillsInfo.resetMagicSchoolCounter();
	skillsInfo.resetWisdomCounter();

	if (ID != Obj::PRISON)
	{
		auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->id)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this);
		if (customApp)
			appearance = customApp.get();
	}

	for(const auto &spec : type->spec) //TODO: unfity with bonus system
	{
		auto bonus = new Bonus();
		bonus->val = spec.val;
		bonus->sid = id.getNum(); //from the hero, specialty has no unique id
		bonus->duration = Bonus::PERMANENT;
		bonus->source = Bonus::HERO_SPECIAL;
		switch (spec.type)
		{
			case 1:// creature specialty
				{
					hs->growsWithLevel = true;

					const CCreature &specCreature = *VLC->creh->creatures[spec.additionalinfo]; //creature in which we have specialty

					//int creLevel = specCreature.level;
					//if(!creLevel)
					//{
					//	if(spec.additionalinfo == 146)
					//		creLevel = 5; //treat ballista as 5-level
					//	else
					//	{
					//        logGlobal->warnStream() << "Warning: unknown level of " << specCreature.namePl;
					//		continue;
					//	}
					//}

					//bonus->additionalInfo = spec.additionalinfo; //creature id, should not be used again - this works only with limiter
					bonus->limiter.reset(new CCreatureTypeLimiter (specCreature, true)); //with upgrades
					bonus->type = Bonus::PRIMARY_SKILL;
					bonus->valType = Bonus::ADDITIVE_VALUE;

					bonus->subtype = PrimarySkill::ATTACK;
					hs->addNewBonus(bonus);

					bonus = new Bonus(*bonus);
					bonus->subtype = PrimarySkill::DEFENSE;
					hs->addNewBonus(bonus);
					//values will be calculated later

					bonus = new Bonus(*bonus);
					bonus->type = Bonus::STACKS_SPEED;
					bonus->val = 1; //+1 speed
					hs->addNewBonus(bonus);
				}
				break;
			case 2://secondary skill
				hs->growsWithLevel = true;
				bonus->type = Bonus::SPECIAL_SECONDARY_SKILL; //needs to be recalculated with level, based on this value
				bonus->valType = Bonus::BASE_NUMBER; // to receive nonzero value
				bonus->subtype = spec.subtype; //skill id
				bonus->val = spec.val; //value per level, in percent
				hs->addNewBonus(bonus);
				bonus = new Bonus(*bonus);

				switch (spec.additionalinfo)
				{
					case 0: //normal
						bonus->valType = Bonus::PERCENT_TO_BASE;
						break;
					case 1: //when it's navigation or there's no 'base' at all
						bonus->valType = Bonus::PERCENT_TO_ALL;
						break;
				}
				bonus->type = Bonus::SECONDARY_SKILL_PREMY; //value will be calculated later
				hs->addNewBonus(bonus);
				break;
			case 3://spell damage bonus, level dependent but calculated elsewhere
				bonus->type = Bonus::SPECIAL_SPELL_LEV;
				bonus->subtype = spec.subtype;
				hs->addNewBonus(bonus);
				break;
			case 4://creature stat boost
				switch (spec.subtype)
				{
					case 1://attack
						bonus->type = Bonus::PRIMARY_SKILL;
						bonus->subtype = PrimarySkill::ATTACK;
						break;
					case 2://defense
						bonus->type = Bonus::PRIMARY_SKILL;
						bonus->subtype = PrimarySkill::DEFENSE;
						break;
					case 3:
						bonus->type = Bonus::CREATURE_DAMAGE;
						bonus->subtype = 0; //both min and max
						break;
					case 4://hp
						bonus->type = Bonus::STACK_HEALTH;
						break;
					case 5:
						bonus->type = Bonus::STACKS_SPEED;
						break;
					default:
						continue;
				}
				bonus->additionalInfo = spec.additionalinfo; //creature id
				bonus->valType = Bonus::ADDITIVE_VALUE;
				bonus->limiter.reset(new CCreatureTypeLimiter (*VLC->creh->creatures[spec.additionalinfo], true));
				hs->addNewBonus(bonus);
				break;
			case 5://spell damage bonus in percent
				bonus->type = Bonus::SPECIFIC_SPELL_DAMAGE;
				bonus->valType = Bonus::BASE_NUMBER; // current spell system is screwed
				bonus->subtype = spec.subtype; //spell id
				hs->addNewBonus(bonus);
				break;
			case 6://damage bonus for bless (Adela)
				bonus->type = Bonus::SPECIAL_BLESS_DAMAGE;
				bonus->subtype = spec.subtype; //spell id if you ever wanted to use it otherwise
				bonus->additionalInfo = spec.additionalinfo; //damage factor
				hs->addNewBonus(bonus);
				break;
			case 7://maxed mastery for spell
				bonus->type = Bonus::MAXED_SPELL;
				bonus->subtype = spec.subtype; //spell i
				hs->addNewBonus(bonus);
				break;
			case 8://peculiar spells - enchantments
				bonus->type = Bonus::SPECIAL_PECULIAR_ENCHANT;
				bonus->subtype = spec.subtype; //spell id
				bonus->additionalInfo = spec.additionalinfo;//0, 1 for Coronius
				hs->addNewBonus(bonus);
				break;
			case 9://upgrade creatures
			{
				const auto &creatures = VLC->creh->creatures;
				bonus->type = Bonus::SPECIAL_UPGRADE;
				bonus->subtype = spec.subtype; //base id
				bonus->additionalInfo = spec.additionalinfo; //target id
				hs->addNewBonus(bonus);
				bonus = new Bonus(*bonus);

				for(auto cre_id : creatures[spec.subtype]->upgrades)
				{
					bonus->subtype = cre_id; //propagate for regular upgrades of base creature
					hs->addNewBonus(bonus);
					bonus = new Bonus(*bonus);
				}
				vstd::clear_pointer(bonus);
				break;
			}
			case 10://resource generation
				bonus->type = Bonus::GENERATE_RESOURCE;
				bonus->subtype = spec.subtype;
				hs->addNewBonus(bonus);
				break;
			case 11://starting skill with mastery (Adrienne)
				setSecSkillLevel(SecondarySkill(spec.val), spec.additionalinfo, true);
				break;
			case 12://army speed
				bonus->type = Bonus::STACKS_SPEED;
				hs->addNewBonus(bonus);
				break;
			case 13://Dragon bonuses (Mutare)
				bonus->type = Bonus::PRIMARY_SKILL;
				bonus->valType = Bonus::ADDITIVE_VALUE;
				switch (spec.subtype)
				{
					case 1:
						bonus->subtype = PrimarySkill::ATTACK;
						break;
					case 2:
						bonus->subtype = PrimarySkill::DEFENSE;
						break;
				}
				bonus->limiter.reset(new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE));
				hs->addNewBonus(bonus);
				break;
			default:
                logGlobal->warnStream() << "Unexpected hero specialty " << type;
		}
	}
	specialty.push_back(hs); //will it work?

	for (auto hs2 : type->specialty) //copy active (probably growing) bonuses from hero prootype to hero object
	{
		auto  hs = new HeroSpecial();
		attachTo(hs); //do we ever need to detach it?

		hs->setNodeType(CBonusSystemNode::SPECIALTY);
		for (auto bonus : hs2.bonuses)
		{
			hs->addNewBonus (bonus);
		}
		hs->growsWithLevel = hs2.growsWithLevel;

		specialty.push_back(hs); //will it work?
	}

	//initialize bonuses
	recreateSecondarySkillsBonuses();
	Updatespecialty();

	mana = manaLimit(); //after all bonuses are taken into account, make sure this line is the last one
	type->name = name;
}
Esempio n. 6
0
std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills() 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 =
		{
			SecondarySkill::FIRE_MAGIC, SecondarySkill::AIR_MAGIC, SecondarySkill::WATER_MAGIC, SecondarySkill::EARTH_MAGIC
		};

		std::shuffle(ss.begin(), ss.end(), skillsInfo.rand.getStdGenerator());

		for (auto skill : ss)
		{
			if (cb->isAllowed(2, skill) && !getSecSkillLevel(skill)) //only schools hero doesn't know yet
			{
				obligatorySkills.push_back(skill);
				break; //only one
			}
		}
	}

	std::vector<SecondarySkill> skills;
	//picking sec. skills for choice
	std::set<SecondarySkill> basicAndAdv, expert, none;
	for(int i=0;i<GameConstants::SKILL_QUANTITY;i++)
		if (cb->isAllowed(2,i))
			none.insert(SecondarySkill(i));

	for(auto & elem : secSkills)
	{
		if(elem.second < SecSkillLevel::EXPERT)
			basicAndAdv.insert(elem.first);
		else
			expert.insert(elem.first);
		none.erase(elem.first);
	}
	for (auto s : obligatorySkills) //don't duplicate them
	{
		none.erase (s);
		basicAndAdv.erase (s);
		expert.erase (s);
	}

	//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.rand)); //new skill
		none.erase(skills.back());
	}
	else if(!basicAndAdv.empty())
	{
		skills.push_back(type->heroClass->chooseSecSkill(basicAndAdv, skillsInfo.rand)); //upgrade existing
		basicAndAdv.erase(skills.back());
	}

	//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.rand);//upgrade existing
		skills.push_back(s);
		basicAndAdv.erase(s);
	}
	else if (canLearnSkill() && obligatorySkills.size() > 1)
	{
		skills.push_back (obligatorySkills[1]);
	}
	else if(none.size() && canLearnSkill())
	{
		skills.push_back(type->heroClass->chooseSecSkill(none, skillsInfo.rand)); //give new skill
		none.erase(skills.back());
	}

	if (skills.size() == 2) // Fix for #1868 to avoid changing logic (possibly causing bugs in process)
		std::swap(skills[0], skills[1]);
	return skills;
}