Esempio n. 1
0
int32 Client::CalcBaseMana()
{
	int WisInt = 0;
	int MindLesserFactor, MindFactor;
	int32 max_m = 0;
	int wisint_mana = 0;
	int base_mana = 0;
	int ConvertedWisInt = 0;
	switch(GetCasterClass())
	{
		case 'I':
			WisInt = GetINT();

				if((( WisInt - 199 ) / 2) > 0)
					MindLesserFactor = ( WisInt - 199 ) / 2;
				else
					MindLesserFactor = 0;

				MindFactor = WisInt - MindLesserFactor;
				if(WisInt > 100)
					max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
				else
					max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
			break;

		case 'W':
			WisInt = GetWIS();


				if((( WisInt - 199 ) / 2) > 0)
					MindLesserFactor = ( WisInt - 199 ) / 2;
				else
					MindLesserFactor = 0;

				MindFactor = WisInt - MindLesserFactor;
				if(WisInt > 100)
					max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
				else
					max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
			break;

		case 'N': {
			max_m = 0;
			break;
		}
		default: {
			Log.Out(Logs::General, Logs::None, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
			max_m = 0;
			break;
		}
	}

#if EQDEBUG >= 11
	Log.Out(Logs::General, Logs::None, "Client::CalcBaseMana() called for %s - returning %d", GetName(), max_m);
#endif
	return max_m;
}
Esempio n. 2
0
/*
	If you change this function, you should update the above function
	to keep the #aggro command accurate.
*/
bool Mob::CheckWillAggro(Mob *mob) {
	if(!mob)
		return false;

	//sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM
	//they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting
	if (mob->IsClient()) {
		if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn())
			return false;
	}

	Mob *ownr = mob->GetOwner();
	if(ownr && ownr->IsClient() && !ownr->CastToClient()->ClientFinishedLoading())
		return false;

	float iAggroRange = GetAggroRange();

	// Check If it's invisible and if we can see invis
	// Check if it's a client, and that the client is connected and not linkdead,
	// and that the client isn't Playing an NPC, with thier gm flag on
	// Check if it's not a Interactive NPC
	// Trumpcard: The 1st 3 checks are low cost calcs to filter out unnessecary distance checks. Leave them at the beginning, they are the most likely occurence.
	// Image: I moved this up by itself above faction and distance checks because if one of these return true, theres no reason to go through the other information

	float t1, t2, t3;
	t1 = mob->GetX() - GetX();
	t2 = mob->GetY() - GetY();
	t3 = mob->GetZ() - GetZ();
	//Cheap ABS()
	if(t1 < 0)
		t1 = 0 - t1;
	if(t2 < 0)
		t2 = 0 - t2;
	if(t3 < 0)
		t3 = 0 - t3;
	if(( t1 > iAggroRange)
		|| ( t2 > iAggroRange)
		|| ( t3 > iAggroRange)
		||(mob->IsInvisible(this))
		|| (mob->IsClient() &&
			(!mob->CastToClient()->Connected()
				|| mob->CastToClient()->IsLD()
				|| mob->CastToClient()->IsBecomeNPC()
				|| mob->CastToClient()->GetGM()
			)
		))
	{
		return(false);
	}

	// Don't aggro new clients if we are already engaged unless PROX_AGGRO is set
	if (IsEngaged() && (!GetSpecialAbility(PROX_AGGRO) || (GetSpecialAbility(PROX_AGGRO) && !CombatRange(mob)))) {
		Log.Out(Logs::Moderate, Logs::Aggro,
			"%s is in combat, and does not have prox_aggro, or does and is out of combat range with %s",
			GetName(), mob->GetName());
		return false;
	}

	//im not sure I understand this..
	//if I have an owner and it is not this mob, then I cannot
	//aggro this mob...???
	//changed to be 'if I have an owner and this is it'
	if(mob == GetOwner()) {
		return(false);
	}

	float dist2 = DistanceSquared(mob->GetPosition(), m_Position);
	float iAggroRange2 = iAggroRange*iAggroRange;

	if( dist2 > iAggroRange2 ) {
		// Skip it, out of range
		return(false);
	}

	//Image: Get their current target and faction value now that its required
	//this function call should seem backwards
	FACTION_VALUE fv = mob->GetReverseFactionCon(this);

	// Make sure they're still in the zone
	// Are they in range?
	// Are they kos?
	// Are we stupid or are they green
	// and they don't have their gm flag on
	int heroicCHA_mod = mob->itembonuses.HeroicCHA/25; // 800 Heroic CHA cap
	if(heroicCHA_mod > THREATENLY_ARRGO_CHANCE)
		heroicCHA_mod = THREATENLY_ARRGO_CHANCE;
	if
	(
	//old InZone check taken care of above by !mob->CastToClient()->Connected()
	(
		( GetINT() <= RuleI(Aggro, IntAggroThreshold) )
		||( mob->IsClient() && mob->CastToClient()->IsSitting() )
		||( mob->GetLevelCon(GetLevel()) != CON_GREEN )

	)
	&&
	(
		(
			fv == FACTION_SCOWLS
			||
			(mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr)
			||
			(
				fv == FACTION_THREATENLY
				&& zone->random.Roll(THREATENLY_ARRGO_CHANCE - heroicCHA_mod)
			)
		)
	)
	)
	{
		//FatherNiwtit: make sure we can see them. last since it is very expensive
		if(CheckLosFN(mob)) {
			Log.Out(Logs::Detail, Logs::Aggro, "Check aggro for %s target %s.", GetName(), mob->GetName());
			return( mod_will_aggro(mob, this) );
		}
	}

	Log.Out(Logs::Detail, Logs::Aggro, "Is In zone?:%d\n", mob->InZone());
	Log.Out(Logs::Detail, Logs::Aggro, "Dist^2: %f\n", dist2);
	Log.Out(Logs::Detail, Logs::Aggro, "Range^2: %f\n", iAggroRange2);
	Log.Out(Logs::Detail, Logs::Aggro, "Faction: %d\n", fv);
	Log.Out(Logs::Detail, Logs::Aggro, "Int: %d\n", GetINT());
	Log.Out(Logs::Detail, Logs::Aggro, "Con: %d\n", GetLevelCon(mob->GetLevel()));

	return(false);
}
Esempio n. 3
0
void NPC::DescribeAggro(Client *towho, Mob *mob, bool verbose) {
	//this logic is duplicated from below, try to keep it up to date.
	float iAggroRange = GetAggroRange();

	float t1, t2, t3;
	t1 = mob->GetX() - GetX();
	t2 = mob->GetY() - GetY();
	t3 = mob->GetZ() - GetZ();
	//Cheap ABS()
	if(t1 < 0)
		t1 = 0 - t1;
	if(t2 < 0)
		t2 = 0 - t2;
	if(t3 < 0)
		t3 = 0 - t3;
	if(( t1 > iAggroRange)
		|| ( t2 > iAggroRange)
		|| ( t3 > iAggroRange) ) {
		towho->Message(0, "...%s is out of range (fast). distances (%.3f,%.3f,%.3f), range %.3f", mob->GetName(),
		t1, t2, t3, iAggroRange);
		return;
	}

	if(mob->IsInvisible(this)) {
		towho->Message(0, "...%s is invisible to me. ", mob->GetName());
		return;
	}
	if((mob->IsClient() &&
		(!mob->CastToClient()->Connected()
		|| mob->CastToClient()->IsLD()
		|| mob->CastToClient()->IsBecomeNPC()
		|| mob->CastToClient()->GetGM()
		)
		))
	{
		towho->Message(0, "...%s is my owner. ", mob->GetName());
		return;
	}


	if(mob == GetOwner()) {
		towho->Message(0, "...%s a GM or is not connected. ", mob->GetName());
		return;
	}

	float dist2 = DistanceSquared(mob->GetPosition(), m_Position);

	float iAggroRange2 = iAggroRange*iAggroRange;
	if( dist2 > iAggroRange2 ) {
		towho->Message(0, "...%s is out of range. %.3f > %.3f ", mob->GetName(),
		dist2, iAggroRange2);
		return;
	}

	if(GetINT() > RuleI(Aggro, IntAggroThreshold) && mob->GetLevelCon(GetLevel()) == CON_GREEN ) {
		towho->Message(0, "...%s is red to me (basically)", mob->GetName(),
		dist2, iAggroRange2);
		return;
	}

	if(verbose) {
		int my_primary = GetPrimaryFaction();
		int mob_primary = mob->GetPrimaryFaction();
		Mob *own = GetOwner();
		if(own != nullptr)
			my_primary = own->GetPrimaryFaction();
		own = mob->GetOwner();
		if(mob_primary > 0 && own != nullptr)
			mob_primary = own->GetPrimaryFaction();

		if(mob_primary == 0) {
			towho->Message(0, "...%s has no primary faction", mob->GetName());
		} else if(mob_primary < 0) {
			towho->Message(0, "...%s is on special faction %d", mob->GetName(), mob_primary);
		} else {
			char namebuf[256];
			if(!database.GetFactionName(mob_primary, namebuf, sizeof(namebuf)))
				strcpy(namebuf, "(Unknown)");
			std::list<struct NPCFaction*>::iterator cur,end;
			cur = faction_list.begin();
			end = faction_list.end();
			bool res = false;
			for(; cur != end; ++cur) {
				struct NPCFaction* fac = *cur;
				if ((int32)fac->factionID == mob_primary) {
					if (fac->npc_value > 0) {
						towho->Message(0, "...%s is on ALLY faction %s (%d) with %d", mob->GetName(), namebuf, mob_primary, fac->npc_value);
						res = true;
						break;
					} else if (fac->npc_value < 0) {
						towho->Message(0, "...%s is on ENEMY faction %s (%d) with %d", mob->GetName(), namebuf, mob_primary, fac->npc_value);
						res = true;
						break;
					} else {
						towho->Message(0, "...%s is on NEUTRAL faction %s (%d) with 0", mob->GetName(), namebuf, mob_primary);
						res = true;
						break;
					}
				}
			}
			if(!res) {
				towho->Message(0, "...%s is on faction %s (%d), which I have no entry for.", mob->GetName(), namebuf, mob_primary);
			}
		}
	}

	FACTION_VALUE fv = mob->GetReverseFactionCon(this);

	if(!(
			fv == FACTION_SCOWLS
			||
			(mob->GetPrimaryFaction() != GetPrimaryFaction() && mob->GetPrimaryFaction() == -4 && GetOwner() == nullptr)
			||
			fv == FACTION_THREATENLY
		)) {
		towho->Message(0, "...%s faction not low enough. value='%s'", mob->GetName(), FactionValueToString(fv));
		return;
	}
	if(fv == FACTION_THREATENLY) {
		towho->Message(0, "...%s threatening to me, so they only have a %d chance per check of attacking.", mob->GetName());
	}

	if(!CheckLosFN(mob)) {
		towho->Message(0, "...%s is out of sight.", mob->GetName());
	}

	towho->Message(0, "...%s meets all conditions, I should be attacking them.", mob->GetName());
}
Esempio n. 4
0
void CPremiumPlayerCtrl::
LoadIniFile(const char* szpIniFileName,struct i3client_t::tagPremiumInfo* pPremium)
{


	char AppName[_MAX_PATH];
	char inStr[_MAX_PATH];
	char Session[_MAX_PATH];	

	
	

	
	
	for(int idx=0; idx < i3client_t::tagPremiumInfo::maxmap_number; idx++){

		wsprintf(AppName,"Map%02d",idx);

		
		::GetPrivateProfileString(AppName,"Allow","YES",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.bAllow = GetBOOL(inStr);

		
		::GetPrivateProfileString(AppName,"iRemainSecond","2147483647",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.iRemainSecond=GetINT(inStr);

		
		::GetPrivateProfileString(AppName,"bDecreseRemainSecond","NO",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.bDecreseRemainSecond=GetBOOL(inStr);

		
		::GetPrivateProfileString(AppName,"bDecreseAllRemainSecond","NO",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.bDecreseAllRemainSecond = GetBOOL(inStr);

		
		::GetPrivateProfileString(AppName,"fAddExpRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.fAddExpRatio = GetFLOAT(inStr);

		
		::GetPrivateProfileString(AppName,"fAddGenExpRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.fAddGenExpRatio = GetFLOAT(inStr);

		
		::GetPrivateProfileString(AppName,"fAddGenCapabilityRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.fAddGenCapabilityRatio=GetFLOAT(inStr);

		
		::GetPrivateProfileString(AppName,"fAddItemDropRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.fAddItemDropRatio =GetFLOAT(inStr);

		
		::GetPrivateProfileString(AppName,"fAddNarkRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Map[idx].Default.fAddNarkRatio = GetFLOAT(inStr);
		

		pPremium->Map[idx].Cur = pPremium->Map[idx].Default;
	}




	
	wsprintf(AppName,"Gameble");
	
	::GetPrivateProfileString(AppName,"fAddPriceRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
	pPremium->Gamble.fAddPriceRatio = GetFLOAT(inStr);

	for(idx=0; idx < i3client_t::tagPremiumInfo::tagGamble::maxnum_apperance_item_group; idx++){
		wsprintf(Session,"Group%02d");
		
		::GetPrivateProfileString(AppName,Session,"YES",inStr,_MAX_PATH,szpIniFileName);
		pPremium->Gamble.ItemGroupArray[idx].bApperance=GetBOOL(inStr);
	}



	wsprintf(AppName,"ItemOptionUpgrade");
	
	
	::GetPrivateProfileString(AppName,"iMaxlevel","10",inStr,_MAX_PATH,szpIniFileName);
	pPremium->ItemOptionUpgrade.iMaxlevel = GetINT(inStr);


	
	::GetPrivateProfileString(AppName,"fAddPriceRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
	pPremium->ItemOptionUpgrade.fAddPriceRatio = GetFLOAT(inStr);	

	
	
	wsprintf(AppName,"Die");
	
	::GetPrivateProfileString(AppName,"fExpRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
	pPremium->Die.fExpRatio = GetFLOAT(inStr);
	
	
	::GetPrivateProfileString(AppName,"fNakRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
	pPremium->Die.fNakRatio = GetFLOAT(inStr);
	



	
	
	::GetPrivateProfileString("PremiumBooth","Use","FALSE",inStr,_MAX_PATH,szpIniFileName);
	pPremium->bCreatePremiumBooth = GetBOOL(inStr);
	


	
	
	::GetPrivateProfileString("ItemCraft","iMaxLevel","10",inStr,_MAX_PATH,szpIniFileName);
	pPremium->iMaxLevelItemCraft = GetINT(inStr);
	


	
	
	::GetPrivateProfileString("ItemPrecocity","TimeRatio","1.0f",inStr,_MAX_PATH,szpIniFileName);
	pPremium->fItemPrecocityTimeRatio = GetFLOAT(inStr);
	


	
	
	::GetPrivateProfileString("ItemRecycle","Use","YES",inStr,_MAX_PATH,szpIniFileName);
	pPremium->bItemRecycle = GetBOOL(inStr);

	
	pPremium->GonyounPracticeBattle.lDate = time(NULL);
	
	::GetPrivateProfileString("GonyounPracticeBattle","iMaxCount","5",inStr,_MAX_PATH,szpIniFileName);
	pPremium->GonyounPracticeBattle.iMaxCount = GetINT(inStr);	
	pPremium->GonyounPracticeBattle.iDecreseCount = pPremium->GonyounPracticeBattle.iMaxCount;



	
	pPremium->WorldChatting.lDate = time(NULL);
	
	::GetPrivateProfileString("WorldChatting","iMaxCount","10",inStr,_MAX_PATH,szpIniFileName);
	pPremium->WorldChatting.iMaxCount = GetINT(inStr);	
	pPremium->WorldChatting.iDecreaseCount = pPremium->WorldChatting.iMaxCount;




	
	
	::GetPrivateProfileString("Status","iDefaultInitCount","1",inStr,_MAX_PATH,szpIniFileName);
	pPremium->Status.iDefaultInitCount= GetINT(inStr);
	
	
	::GetPrivateProfileString("Status","iInitCount","1000",inStr,_MAX_PATH,szpIniFileName);
	pPremium->Status.iInitCount=GetINT(inStr);

}
Esempio n. 5
0
int32 Client::CalcBaseMana()
{
	int WisInt = 0;
	int MindLesserFactor, MindFactor;
	int32 max_m = 0;
	int wisint_mana = 0;
	int base_mana = 0;
	int ConvertedWisInt = 0;
	switch(GetCasterClass())
	{
		case 'I':
			WisInt = GetINT();

			if (GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {

				if (WisInt > 100) {
					ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
					if (WisInt > 201) {
						ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
					}
				}
				else {
					ConvertedWisInt = WisInt;
				}

				auto base_data = database.GetBaseData(GetLevel(), GetClass());
				if(base_data) {
					max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicINT() * 10);
				}
			}
			else
			{
				if((( WisInt - 199 ) / 2) > 0)
					MindLesserFactor = ( WisInt - 199 ) / 2;
				else
					MindLesserFactor = 0;

				MindFactor = WisInt - MindLesserFactor;
				if(WisInt > 100)
					max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
				else
					max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
			}
			break;

		case 'W':
			WisInt = GetWIS();

			if (GetClientVersion() >= EQClientSoF && RuleB(Character, SoDClientUseSoDHPManaEnd)) {

				if (WisInt > 100) {
					ConvertedWisInt = (((WisInt - 100) * 5 / 2) + 100);
					if (WisInt > 201) {
						ConvertedWisInt -= ((WisInt - 201) * 5 / 4);
					}
				}
				else {
					ConvertedWisInt = WisInt;
				}

				auto base_data = database.GetBaseData(GetLevel(), GetClass());
				if(base_data) {
					max_m = base_data->base_mana + (ConvertedWisInt * base_data->mana_factor) + (GetHeroicWIS() * 10);
				}
			}
			else
			{
				if((( WisInt - 199 ) / 2) > 0)
					MindLesserFactor = ( WisInt - 199 ) / 2;
				else
					MindLesserFactor = 0;

				MindFactor = WisInt - MindLesserFactor;
				if(WisInt > 100)
					max_m = (((5 * (MindFactor + 20)) / 2) * 3 * GetLevel() / 40);
				else
					max_m = (((5 * (MindFactor + 200)) / 2) * 3 * GetLevel() / 100);
			}
			break;

		case 'N': {
			max_m = 0;
			break;
		}
		default: {
			LogFile->write(EQEMuLog::Debug, "Invalid Class '%c' in CalcMaxMana", GetCasterClass());
			max_m = 0;
			break;
		}
	}

#if EQDEBUG >= 11
	LogFile->write(EQEMuLog::Debug, "Client::CalcBaseMana() called for %s - returning %d", GetName(), max_m);
#endif
	return max_m;
}
Esempio n. 6
0
//returns true on success
bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
 	if(spec == NULL)
		return(false);
	
	uint16 user_skill = GetSkill(spec->tradeskill);
	float chance = 0.0;
	float skillup_modifier = 0.0;
	int16 thirdstat = 0;
	int16 stat_modifier = 15;
	uint16 success_modifier = 0;

	// Rework based on the info on eqtraders.com
	// http://mboards.eqtraders.com/eq/showthread.php?t=22246
	// 09/10/2006 v0.1 (eq4me)
	// 09/11/2006 v0.2 (eq4me)
	// Todo:
	//     Implementing AAs
	//     Success modifiers based on recipes
	//     Skillup modifiers based on the rarity of the ingredients

	// Some tradeskills are more eqal then others. ;-)
	// If you want to customize the stage1 success rate do it here.
    // Remember: skillup_modifier is (float). Lower is better
	switch(spec->tradeskill) {
	case FLETCHING:
	case ALCHEMY:
	case JEWELRY_MAKING:
	case POTTERY:
		skillup_modifier = 4;
		break;
	case BAKING:
	case BREWING:
		skillup_modifier = 3;
		break;
	case RESEARCH:
		skillup_modifier = 1;
		break;
	default:
		skillup_modifier = 2;
		break;
	}

	// Some tradeskills take the higher of one additional stat beside INT and WIS
	// to determine the skillup rate. Additionally these tradeskills do not have an
	// -15 modifier on their statbonus.
	if (spec->tradeskill ==  FLETCHING || spec->tradeskill == MAKE_POISON) {
		thirdstat = GetDEX();
		stat_modifier = 0;
	} else if (spec->tradeskill == BLACKSMITHING) {
		thirdstat = GetSTR();
		stat_modifier = 0;
	}
	
	int16 higher_from_int_wis = (GetINT() > GetWIS()) ? GetINT() : GetWIS();
	int16 bonusstat = (higher_from_int_wis > thirdstat) ? higher_from_int_wis : thirdstat;
	
	vector< pair<uint32,uint8> >::iterator itr;


    //calculate the base success chance
	// For trivials over 68 the chance is (skill - 0.75*trivial) +51.5
    // For trivial up to 68 the chance is (skill - trivial) + 66
	if (spec->trivial >= 68) {
		chance = (user_skill - (0.75*spec->trivial)) + 51.5;
	} else {
		chance = (user_skill - spec->trivial) + 66;
	}
	
	int16 over_trivial = (int16)GetRawSkill(spec->tradeskill) - (int16)spec->trivial;

	//handle caps
	if(spec->nofail) {
		chance = 100;	//cannot fail.
		_log(TRADESKILLS__TRACE, "...This combine cannot fail.");
	} else if(over_trivial >= 0) {
		// At reaching trivial the chance goes to 95% going up an additional
		// percent for every 40 skillpoints above the trivial.
		// The success rate is not modified through stats.
		// Mastery AAs are unaccounted for so far.
		// chance_AA = chance + ((100 - chance) * mastery_modifier)
		// But the 95% limit with an additional 1% for every 40 skill points
		// above critical still stands.
		// Mastery modifier is: 10%/25%/50% for rank one/two/three
		chance = 95.0f + (float(user_skill - spec->trivial) / 40.0f);
		Message_StringID(MT_Emote, TRADESKILL_TRIVIAL);
	} else if(chance < 5) {
		// Minimum chance is always 5
		chance = 5;
	} else if(chance > 95) {
		//cap is 95, shouldent reach this before trivial, but just in case.
		chance = 95;
	}
	
	_log(TRADESKILLS__TRACE, "...Current skill: %d , Trivial: %d , Success chance: %f percent", user_skill , spec->trivial , chance);
	_log(TRADESKILLS__TRACE, "...Bonusstat: %d , INT: %d , WIS: %d , DEX: %d , STR: %d", bonusstat , GetINT() , GetWIS() , GetDEX() , GetSTR());
	
	float res = MakeRandomFloat(0, 99);
	int AAChance = 0;

	//AA modifiers
	//can we do this with nested switches?
	if(spec->tradeskill == ALCHEMY){
		switch(GetAA(aaAlchemyMastery)){
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if(spec->tradeskill == JEWELRY_MAKING){
		switch(GetAA(aaJewelCraftMastery)){
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}
      const Item_Struct* item = NULL;

	if (spec->tradeskill == BLACKSMITHING) {
		switch(GetAA(aaBlacksmithingMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == BAKING) {
		switch(GetAA(aaBakingMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == BREWING) {
		switch(GetAA(aaBrewingMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == FLETCHING) {
		switch(GetAA(aaFletchingMastery2)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == POTTERY) {
		switch(GetAA(aaPotteryMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (spec->tradeskill == TAILORING) {
		switch(GetAA(aaTailoringMastery)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}
	
	if (spec->tradeskill == RESEARCH) {
		switch(GetAA(aaArcaneTongues)) {
		case 1:
			AAChance = 10;
			break;
		case 2:
			AAChance = 25;
			break;
		case 3:
			AAChance = 50;
			break;
		}
	}

	if (((spec->tradeskill==75) || GetGM() || (chance > res)) || MakeRandomInt(0, 99) < AAChance){
		success_modifier = 1;
		
		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);
		
		Message_StringID(4,TRADESKILL_SUCCEED,spec->name.c_str());

		_log(TRADESKILLS__TRACE, "Tradeskill success");

		itr = spec->onsuccess.begin();
		while(itr != spec->onsuccess.end() && !spec->quest) {
			//should we check this crap?
			SummonItem(itr->first, itr->second);
                  item = database.GetItem(itr->first);
			if (this->GetGroup())
			{
				entity_list.MessageGroup(this,true,MT_Skills,"%s has successfully fashioned %s!",GetName(),item->Name);
			}
			if(RuleB(TaskSystem, EnableTaskSystem))
				UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second);
			itr++;
		}
		return(true);
	} else {
		success_modifier = 2; // Halves the chance
		
		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);
		
		Message_StringID(MT_Emote,TRADESKILL_FAILED);

		_log(TRADESKILLS__TRACE, "Tradeskill failed");
            if (this->GetGroup())
		{
			entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its");
		}
		
		itr = spec->onfail.begin();
		while(itr != spec->onfail.end()) {
			//should we check these arguments?
			SummonItem(itr->first, itr->second);
			itr++;
		}

        // Rolls on each item, is possible to return everything
        int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance;
        // Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways
        if(SalvageChance && spec->tradeskill != 75 && !spec->quest) {
            itr = spec->salvage.begin();
            uint8 sc = 0;
            while(itr != spec->salvage.end()) {
                for(sc = 0; sc < itr->second; sc++)
                    if(MakeRandomInt(0,99) < SalvageChance)
                        SummonItem(itr->first, 1);
                itr++;
            }
        }

	}
	return(false);
}
Esempio n. 7
0
//returns true on success
bool Client::TradeskillExecute(DBTradeskillRecipe_Struct *spec) {
	if(spec == nullptr)
		return(false);

	uint16 user_skill = GetSkill(spec->tradeskill);
	float chance = 0.0;
	float skillup_modifier = 0.0;
	int16 thirdstat = 0;
	int16 stat_modifier = 15;
	uint16 success_modifier = 0;

	// Rework based on the info on eqtraders.com
	// http://mboards.eqtraders.com/eq/showthread.php?t=22246
	// 09/10/2006 v0.1 (eq4me)
	// 09/11/2006 v0.2 (eq4me)
	// Todo:
	// Implementing AAs
	// Success modifiers based on recipes
	// Skillup modifiers based on the rarity of the ingredients

	// Some tradeskills are more eqal then others. ;-)
	// If you want to customize the stage1 success rate do it here.
	// Remember: skillup_modifier is (float). Lower is better
        switch(spec->tradeskill) {
        case SkillFletching:
                skillup_modifier = RuleI(Character, TradeskillUpFletching);
                break;
        case SkillAlchemy:
                skillup_modifier = RuleI(Character, TradeskillUpAlchemy);
                break;
        case SkillJewelryMaking:
                skillup_modifier = RuleI(Character, TradeskillUpJewelcrafting);
                break;
        case SkillPottery:
                skillup_modifier = RuleI(Character, TradeskillUpPottery);
                break;
        case SkillBaking:
                skillup_modifier = RuleI(Character, TradeskillUpBaking);
                break;
        case SkillBrewing:
                skillup_modifier = RuleI(Character, TradeskillUpBrewing);
                break;
        case SkillBlacksmithing:
                skillup_modifier = RuleI(Character, TradeskillUpBlacksmithing);
                break;
        case SkillResearch:
                skillup_modifier = RuleI(Character, TradeskillUpResearch);
                break;
        case SkillMakePoison:
                skillup_modifier = RuleI(Character, TradeskillUpMakePoison);
                break;
        case SkillTinkering:
                skillup_modifier = RuleI(Character, TradeskillUpTinkering);
                break;
        default:
                skillup_modifier = 2;
                break;
        }

	// Some tradeskills take the higher of one additional stat beside INT and WIS
	// to determine the skillup rate. Additionally these tradeskills do not have an
	// -15 modifier on their statbonus.
	if (spec->tradeskill == SkillFletching || spec->tradeskill == SkillMakePoison) {
		thirdstat = GetDEX();
		stat_modifier = 0;
	} else if (spec->tradeskill == SkillBlacksmithing) {
		thirdstat = GetSTR();
		stat_modifier = 0;
	}

	int16 higher_from_int_wis = (GetINT() > GetWIS()) ? GetINT() : GetWIS();
	int16 bonusstat = (higher_from_int_wis > thirdstat) ? higher_from_int_wis : thirdstat;

	std::vector< std::pair<uint32,uint8> >::iterator itr;


	//calculate the base success chance
	// For trivials over 68 the chance is (skill - 0.75*trivial) +51.5
	// For trivial up to 68 the chance is (skill - trivial) + 66
	if (spec->trivial >= 68) {
		chance = (user_skill - (0.75*spec->trivial)) + 51.5;
	} else {
		chance = (user_skill - spec->trivial) + 66;
	}

	int16 over_trivial = (int16)GetRawSkill(spec->tradeskill) - (int16)spec->trivial;

	//handle caps
	if(spec->nofail) {
		chance = 100;	//cannot fail.
		Log.Out(Logs::Detail, Logs::Tradeskills, "...This combine cannot fail.");
	} else if(over_trivial >= 0) {
		// At reaching trivial the chance goes to 95% going up an additional
		// percent for every 40 skillpoints above the trivial.
		// The success rate is not modified through stats.
		// Mastery AAs are unaccounted for so far.
		// chance_AA = chance + ((100 - chance) * mastery_modifier)
		// But the 95% limit with an additional 1% for every 40 skill points
		// above critical still stands.
		// Mastery modifier is: 10%/25%/50% for rank one/two/three
		chance = 95.0f + (float(user_skill - spec->trivial) / 40.0f);
		Message_StringID(MT_Emote, TRADESKILL_TRIVIAL);
	} else if(chance < 5) {
		// Minimum chance is always 5
		chance = 5;
	} else if(chance > 95) {
		//cap is 95, shouldent reach this before trivial, but just in case.
		chance = 95;
	}

	Log.Out(Logs::Detail, Logs::Tradeskills, "...Current skill: %d , Trivial: %d , Success chance: %f percent", user_skill , spec->trivial , chance);
	Log.Out(Logs::Detail, Logs::Tradeskills, "...Bonusstat: %d , INT: %d , WIS: %d , DEX: %d , STR: %d", bonusstat , GetINT() , GetWIS() , GetDEX() , GetSTR());

	float res = zone->random.Real(0, 99);
	int aa_chance = 0;

	aa_chance = spellbonuses.ReduceTradeskillFail[spec->tradeskill] + itembonuses.ReduceTradeskillFail[spec->tradeskill] + aabonuses.ReduceTradeskillFail[spec->tradeskill];

	const Item_Struct* item = nullptr;
	
	chance = mod_tradeskill_chance(chance, spec);

	if (((spec->tradeskill==75) || GetGM() || (chance > res)) || zone->random.Roll(aa_chance)) {
		success_modifier = 1;

		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);

		Message_StringID(4, TRADESKILL_SUCCEED, spec->name.c_str());

		Log.Out(Logs::Detail, Logs::Tradeskills, "Tradeskill success");

		itr = spec->onsuccess.begin();
		while(itr != spec->onsuccess.end() && !spec->quest) {
			//should we check this crap?
			SummonItem(itr->first, itr->second);
			item = database.GetItem(itr->first);
			if (this->GetGroup()) {
				entity_list.MessageGroup(this, true, MT_Skills, "%s has successfully fashioned %s!", GetName(), item->Name);
			}

			/* QS: Player_Log_Trade_Skill_Events */
			if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
				std::string event_desc = StringFormat("Success :: fashioned recipe_id:%i tskillid:%i trivial:%i chance:%4.2f  in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
				QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
			}

			if(RuleB(TaskSystem, EnableTaskSystem))
				UpdateTasksForItem(ActivityTradeSkill, itr->first, itr->second);
			++itr;
		}
		return(true);
	}
	/* Tradeskill Fail */
	else {
		success_modifier = 2; // Halves the chance

		if(over_trivial < 0)
			CheckIncreaseTradeskill(bonusstat, stat_modifier, skillup_modifier, success_modifier, spec->tradeskill);

		Message_StringID(MT_Emote,TRADESKILL_FAILED);

		Log.Out(Logs::Detail, Logs::Tradeskills, "Tradeskill failed");
			if (this->GetGroup())
		{
			entity_list.MessageGroup(this,true,MT_Skills,"%s was unsuccessful in %s tradeskill attempt.",GetName(),this->GetGender() == 0 ? "his" : this->GetGender() == 1 ? "her" : "its");

		}

		/* QS: Player_Log_Trade_Skill_Events */
		if (RuleB(QueryServ, PlayerLogTradeSkillEvents)){
			std::string event_desc = StringFormat("Failed :: recipe_id:%i tskillid:%i trivial:%i chance:%4.2f  in zoneid:%i instid:%i", spec->recipe_id, spec->tradeskill, spec->trivial, chance, this->GetZoneID(), this->GetInstanceID());
			QServ->PlayerLogEvent(Player_Log_Trade_Skill_Events, this->CharacterID(), event_desc);
		}

		itr = spec->onfail.begin();
		while(itr != spec->onfail.end()) {
			//should we check these arguments?
			SummonItem(itr->first, itr->second);
			++itr;
		}

		/* Salvage Item rolls */

		// Rolls on each item, is possible to return everything
		int SalvageChance = aabonuses.SalvageChance + itembonuses.SalvageChance + spellbonuses.SalvageChance;
		// Skip check if not a normal TS or if a quest recipe these should be nofail, but check amyways
		if(SalvageChance && spec->tradeskill != 75 && !spec->quest) {
			itr = spec->salvage.begin();
			uint8 sc = 0;
			while(itr != spec->salvage.end()) {
				for(sc = 0; sc < itr->second; sc++)
					if(zone->random.Roll(SalvageChance))
						SummonItem(itr->first, 1);
				++itr;
			}
		}

	}
	return(false);
}