Exemplo n.º 1
0
CArtifactInstance *CArtifactInstance::createScroll(SpellID sid)
{
	auto ret = new CArtifactInstance(VLC->arth->artifacts[ArtifactID::SPELL_SCROLL]);
	auto b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT_INSTANCE, -1, ArtifactID::SPELL_SCROLL, sid);
	ret->addNewBonus(b);
	return ret;
}
Exemplo n.º 2
0
CArtifactInstance * CArtifactInstance::createScroll( const CSpell *s)
{
	auto ret = new CArtifactInstance(VLC->arth->artifacts[1]);
	auto b = new Bonus(Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT_INSTANCE, -1, 1, s->id);
	ret->addNewBonus(b);
	return ret;
}
Exemplo n.º 3
0
CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
{
	if(!Art->constituents)
	{
		auto  ret = new CArtifactInstance(Art);
		if (dynamic_cast<CGrowingArtifact *>(Art))
		{
			auto bonus = std::make_shared<Bonus>();
			bonus->type = Bonus::LEVEL_COUNTER;
			bonus->val = 0;
			ret->addNewBonus (bonus);
		}
		return ret;
	}
	else
	{
		auto  ret = new CCombinedArtifactInstance(Art);
		ret->createConstituents();
		return ret;
	}
}
Exemplo n.º 4
0
void CArmedInstance::updateMoraleBonusFromArmy()
{
	if(!validTypes(false)) //object not randomized, don't bother
		return;

	auto b = getExportedBonusList().getFirst(Selector::sourceType(Bonus::ARMY).And(Selector::type(Bonus::MORALE)));
 	if(!b)
	{
		b = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, 0, -1);
		addNewBonus(b);
	}

	//number of alignments and presence of undead
	std::set<TFaction> factions;
	bool hasUndead = false;

	for(auto slot : Slots())
	{
		const CStackInstance * inst = slot.second;
		const CCreature * creature  = VLC->creh->creatures[inst->getCreatureID()];

		factions.insert(creature->faction);
		// Check for undead flag instead of faction (undead mummies are neutral)
		hasUndead |= inst->hasBonusOfType(Bonus::UNDEAD);
	}

	size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account

	// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
	if (hasBonusOfType(Bonus::NONEVIL_ALIGNMENT_MIX))
	{
		size_t mixableFactions = 0;

		for(TFaction f : factions)
		{
			if (VLC->townh->factions[f]->alignment != EAlignment::EVIL)
				mixableFactions++;
		}
		if (mixableFactions > 0)
			factionsInArmy -= mixableFactions - 1;
	}

	if(factionsInArmy == 1)
	{
		b->val = +1;
		b->description = VLC->generaltexth->arraytxt[115]; //All troops of one alignment +1
		b->description = b->description.substr(0, b->description.size()-3);//trim "+1"
	}
	else if (!factions.empty()) // no bonus from empty garrison
	{
	 	b->val = 2 - factionsInArmy;
		b->description = boost::str(boost::format(VLC->generaltexth->arraytxt[114]) % factionsInArmy % b->val); //Troops of %d alignments %d
		b->description = b->description.substr(0, b->description.size()-2);//trim value
	}
	boost::algorithm::trim(b->description);
	CBonusSystemNode::treeHasChanged();

	//-1 modifier for any Undead unit in army
	const ui8 UNDEAD_MODIFIER_ID = -2;
	auto undeadModifier = getExportedBonusList().getFirst(Selector::source(Bonus::ARMY, UNDEAD_MODIFIER_ID));
 	if(hasUndead)
	{
		if(!undeadModifier)
		{
			undeadModifier = std::make_shared<Bonus>(Bonus::PERMANENT, Bonus::MORALE, Bonus::ARMY, -1, UNDEAD_MODIFIER_ID, VLC->generaltexth->arraytxt[116]);
			undeadModifier->description = undeadModifier->description.substr(0, undeadModifier->description.size()-2);//trim value
			addNewBonus(undeadModifier);
		}
	}
	else if(undeadModifier)
		removeBonus(undeadModifier);

}
Exemplo n.º 5
0
void CGHeroInstance::updateSkill(SecondarySkill which, int val)
{
	if(which == SecondarySkill::LEADERSHIP || which == SecondarySkill::LUCK)
	{ //luck-> VLC->generaltexth->arraytxt[73+luckSkill]; VLC->generaltexth->arraytxt[104+moraleSkill]
		bool luck = which == SecondarySkill::LUCK;
		Bonus::BonusType type[] = {Bonus::MORALE, Bonus::LUCK};

		Bonus *b = getBonusLocalFirst(Selector::type(type[luck]).And(Selector::sourceType(Bonus::SECONDARY_SKILL)));
		if(!b)
		{
			b = new Bonus(Bonus::PERMANENT, type[luck], Bonus::SECONDARY_SKILL, +val, which, which, Bonus::BASE_NUMBER);
			addNewBonus(b);
		}
		else
			b->val = +val;
	}
	else if(which == SecondarySkill::DIPLOMACY) //surrender discount: 20% per level
	{

		if(Bonus *b = getBonusLocalFirst(Selector::type(Bonus::SURRENDER_DISCOUNT).And(Selector::sourceType(Bonus::SECONDARY_SKILL))))
			b->val = +val;
		else
			addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::SURRENDER_DISCOUNT, Bonus::SECONDARY_SKILL, val * 20, which));
	}

	int skillVal = 0;
	switch (which)
	{
	case SecondarySkill::ARCHERY:
		switch (val)
		{
		case 1:
			skillVal = 10; break;
		case 2:
			skillVal = 25; break;
		case 3:
			skillVal = 50; break;
		}
		break;
	case SecondarySkill::LOGISTICS:
		skillVal = 10 * val; break;
	case SecondarySkill::NAVIGATION:
		skillVal = 50 * val; break;
	case SecondarySkill::MYSTICISM:
		skillVal = val; break;
	case SecondarySkill::EAGLE_EYE:
		skillVal = 30 + 10 * val; break;
	case SecondarySkill::NECROMANCY:
		skillVal = 10 * val; break;
	case SecondarySkill::LEARNING:
		skillVal = 5 * val; break;
	case SecondarySkill::OFFENCE:
		skillVal = 10 * val; break;
	case SecondarySkill::ARMORER:
		skillVal = 5 * val; break;
	case SecondarySkill::INTELLIGENCE:
		skillVal = 25 << (val-1); break;
	case SecondarySkill::SORCERY:
		skillVal = 5 * val; break;
	case SecondarySkill::RESISTANCE:
		skillVal = 5 << (val-1); break;
	case SecondarySkill::FIRST_AID:
		skillVal = 25 + 25*val; break;
	case SecondarySkill::ESTATES:
		skillVal = 125 << (val-1); break;
	}


	Bonus::ValueType skillValType = skillVal ? Bonus::BASE_NUMBER : Bonus::INDEPENDENT_MIN;
	if(Bonus * b = getBonusList().getFirst(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, which)
										.And(Selector::sourceType(Bonus::SECONDARY_SKILL)))) //only local hero bonus
	{
		b->val = skillVal;
		b->valType = skillValType;
	}
	else
	{
		auto bonus = new Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, Bonus::SECONDARY_SKILL, skillVal, id.getNum(), which, skillValType);
		bonus->source = Bonus::SECONDARY_SKILL;
		addNewBonus(bonus);
	}

}
Exemplo n.º 6
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;
}
Exemplo n.º 7
0
void CGHeroInstance::pushPrimSkill( PrimarySkill::PrimarySkill which, int val )
{
	assert(!hasBonus(Selector::typeSubtype(Bonus::PRIMARY_SKILL, which)
						.And(Selector::sourceType(Bonus::HERO_BASE_SKILL))));
	addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id.getNum(), which));
}