示例#1
0
int32 Client::GetActSpellDuration(uint16 spell_id, int32 duration)
{
    int increase = 100;
    increase += GetFocusEffect(focusSpellDuration, spell_id);
    int tic_inc = 0;
    tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);

    if(IsBeneficialSpell(spell_id))
    {
        switch(GetAA(aaSpellCastingReinforcement)) {
        case 1:
            increase += 5;
            break;
        case 2:
            increase += 15;
            break;
        case 3:
            increase += 30;
            if (GetAA(aaSpellCastingReinforcementMastery) == 1)
                increase += 20;
            break;
        }
    }

    if(IsMezSpell(spell_id)) {
        tic_inc += GetAA(aaMesmerizationMastery);
    }

    return (((duration * increase) / 100) + tic_inc);
}
示例#2
0
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {

    if (target == nullptr)
        return value;

    int32 value_BaseEffect = 0;
    int32 extra_dmg = 0;
    int16 chance = 0;
    chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance;

    if (spellbonuses.CriticalDotDecay)
        chance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay);

    value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);

    if (chance > 0 && (zone->random.Roll(chance))) {
        int32 ratio = 200;
        ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
        value = value_BaseEffect*ratio/100;
        value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
        value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
        value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
        extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
                    int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
                    GetFocusEffect(focusFcDamageAmt, spell_id);

        if (extra_dmg) {
            int duration = CalcBuffDuration(this, this, spell_id);
            if (duration > 0)
                extra_dmg /= duration;
        }

        value -= extra_dmg;

        return value;
    }

    value = value_BaseEffect;
    value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
    value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
    value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
    extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
                GetFocusEffect(focusFcDamageAmtCrit, spell_id) +
                GetFocusEffect(focusFcDamageAmt, spell_id);

    if (extra_dmg) {
        int duration = CalcBuffDuration(this, this, spell_id);
        if (duration > 0)
            extra_dmg /= duration;
    }

    value -= extra_dmg;

    return value;
}
示例#3
0
int32 Client::Additional_Heal(uint16 spell_id)
{
    int32 heal_amt = 0;

    heal_amt  += GetFocusEffect(focusAdditionalHeal, spell_id);
    heal_amt  += GetFocusEffect(focusAdditionalHeal2, spell_id);

    if (heal_amt) {
        int duration = CalcBuffDuration(this, this, spell_id);
        if (duration > 0)
            return heal_amt /= duration;
    }

    return heal_amt;
}
示例#4
0
//healing and buffing aggro
int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possible)
{
	int32 AggroAmount = 0;
	auto target_level = target ? target->GetLevel() : 1;
	bool ignore_default_buff = false; // rune/hot don't use the default 9, HP buffs that heal (virtue) do use the default

	for (int o = 0; o < EFFECT_COUNT; o++) {
		switch (spells[spell_id].effectid[o]) {
		case SE_CurrentHP: {
			if (heal_possible == 0) {
				AggroAmount += 1;
				break;
			}
			// hate based on base healing power of the spell
			int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o],
							 spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id);
			if (val > 0) {
				if (heal_possible < val)
					val = heal_possible; // capped to amount healed
				val = 2 * val / 3; // 3:2 ratio

				if (target_level > 50 && val > 1500)
					val = 1500; // target 51+ seems ~1500
				else if (target_level <= 50 && val > 800)
					val = 800; // per live patch notes, capped to 800
			}
			AggroAmount += std::max(val, 1);
			break;
		}
		case SE_Rune:
			AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o],
							 spells[spell_id].base[o], spells[spell_id].max[o], GetLevel(), spell_id) * 2;
			ignore_default_buff = true;
			break;
		case SE_HealOverTime:
			AggroAmount += 10;
			ignore_default_buff = true;
			break;
		default:
			break;
		}
	}
	if (GetOwner() && IsPet())
		AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;

	if (!ignore_default_buff && IsBuffSpell(spell_id) && IsBeneficialSpell(spell_id))
		AggroAmount = IsBardSong(spell_id) ? 2 : 9;

	if (AggroAmount > 0) {
		int HateMod = RuleI(Aggro, SpellAggroMod);
		HateMod += GetFocusEffect(focusSpellHateMod, spell_id);

		//Live AA - Spell casting subtlety
		HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod;

		AggroAmount = (AggroAmount * HateMod) / 100;
	}

	return std::max(0, AggroAmount);
}
示例#5
0
int32 Client::GetActDoTDamage(uint16 spell_id, int32 value) {

    int32 modifier = 100;
    int16 spell_dmg = 0;
    int16 critChance = 0;
    int32 ratio = 0;

    modifier += GetFocusEffect(focusImprovedDamage, spell_id);
    critChance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance;
    ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
    spell_dmg += Additional_SpellDmg(spell_id,true);

    // since DOTs are the Necromancer forte, give an innate bonus (Kayen: Is this a real bonus?)
    // however, no chance to crit unless they've trained atleast one level in the AA first
    if (GetClass() == NECROMANCER && critChance > 0)
        critChance += 5;

    if (critChance > 0) {
        if (MakeRandomInt(0, 99) < critChance) {
            modifier += modifier*ratio/100;
            return (((value*modifier/100)-spell_dmg)*2);
        }
    }

    return ((value*modifier/100)-spell_dmg);

}
示例#6
0
int32 Client::Additional_SpellDmg(uint16 spell_id, bool bufftick)
{
    int32 spell_dmg = 0;
    spell_dmg  += GetFocusEffect(focusFF_Damage_Amount, spell_id);
    spell_dmg  += GetFocusEffect(focusSpellDamage, spell_id);

    //For DOTs you need to apply the damage over the duration of the dot to each tick (this is how live did it)
    if (bufftick) {
        int duration = CalcBuffDuration(this, this, spell_id);
        if (duration > 0)
            return spell_dmg /= duration;
        else
            return 0;
    }
    return spell_dmg;
}
示例#7
0
float Client::GetActSpellRange(uint16 spell_id, float range, bool IsBard)
{
    float extrange = 100;

    extrange += GetFocusEffect(focusRange, spell_id);

    return (range * extrange) / 100;
}
示例#8
0
int32 Client::GetActSpellHealing(uint16 spell_id, int32 value) {

    int32 modifier = 100;
    int16 heal_amt = 0;
    modifier += GetFocusEffect(focusImprovedHeal, spell_id);
    modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
    heal_amt += Additional_Heal(spell_id);
    int chance = 0;

    // Instant Heals
    if(spells[spell_id].buffduration < 1)
    {
        // Formula = HealAmt * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant heal more than the spell itself.
        if(this->itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
            heal_amt = this->itembonuses.HealAmt * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
            if(heal_amt > value)
                heal_amt = value;
        }

        // Check for buffs that affect the healrate of the target and critical heal rate of target
        if(GetTarget()) {
            value += value * GetHealRate(spell_id) / 100;
            chance += GetCriticalHealRate(spell_id);
        }

        //Live AA - Healing Gift, Theft of Life
        chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;

        if(MakeRandomInt(0,99) < chance) {
            entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s performs an exceptional heal! (%d)", GetName(), ((value * modifier / 50) + heal_amt*2));
            return ((value * modifier / 50) + heal_amt*2);
        }
        else {
            return ((value * modifier / 100) + heal_amt);
        }
    }
    // Hots
    else {
        chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;
        if(MakeRandomInt(0,99) < chance)
            return ((value * modifier / 50) + heal_amt*2);
    }
    return ((value * modifier / 100) + heal_amt);
}
示例#9
0
int32 Mob::GetActSpellDuration(uint16 spell_id, int32 duration)
{
	if (spells[spell_id].not_extendable)
		return duration;

	int increase = 100;
	increase += GetFocusEffect(focusSpellDuration, spell_id);
	int tic_inc = 0;
	tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);

	float focused = ((duration * increase) / 100.0f) + tic_inc;
	int ifocused = static_cast<int>(focused);

	// 7.6 is rounded to 7, 8.6 is rounded to 9
	// 6 is 6, etc
	if (FCMP(focused, ifocused) || ifocused % 2) // equal or odd
		return ifocused;
	else // even and not equal round to odd
		return ifocused + 1;
}
示例#10
0
int32 Client::GetActSpellDuration(uint16 spell_id, int32 duration)
{
	if (spells[spell_id].not_extendable)
		return duration;

	int increase = 100;
	increase += GetFocusEffect(focusSpellDuration, spell_id);
	int tic_inc = 0;
	tic_inc = GetFocusEffect(focusSpellDurByTic, spell_id);

	// Only need this for clients, since the change was for bard songs, I assume we should keep non bard songs getting +1
	// However if its bard or not and is mez, charm or fear, we need to add 1 so that client is in sync
	if (!(IsShortDurationBuff(spell_id) && IsBardSong(spell_id)) ||
			IsFearSpell(spell_id) ||
			IsCharmSpell(spell_id) ||
			IsMezSpell(spell_id) ||
			IsBlindSpell(spell_id))
		tic_inc += 1;

	return (((duration * increase) / 100) + tic_inc);
}
示例#11
0
int32 Client::GetActSpellCasttime(uint16 spell_id, int32 casttime)
{
    int32 cast_reducer = 0;
    cast_reducer += GetFocusEffect(focusSpellHaste, spell_id);

    //this function loops through the effects of spell_id many times
    //could easily be consolidated.

    if (GetLevel() >= 51 && casttime >= 3000 && !BeneficialSpell(spell_id)
            && (GetClass() == SHADOWKNIGHT || GetClass() == RANGER
                || GetClass() == PALADIN || GetClass() == BEASTLORD ))
        cast_reducer += (GetLevel()-50)*3;

    //LIVE AA SpellCastingDeftness, QuickBuff, QuickSummoning, QuickEvacuation, QuickDamage

    if (cast_reducer > RuleI(Spells, MaxCastTimeReduction))
        cast_reducer = RuleI(Spells, MaxCastTimeReduction);

    casttime = (casttime*(100 - cast_reducer)/100);

    return casttime;
}
示例#12
0
int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
{
    // This formula was derived from the following resource:
    // http://www.eqsummoners.com/eq1/specialization-library.html
    // WildcardX
    float PercentManaReduction = 0.0f;
    float SpecializeSkill = GetSpecializeSkillValue(spell_id);

    if (SpecializeSkill > 0.0f)
    {
        PercentManaReduction = 1 + SpecializeSkill / 20.0f;
        switch(GetAA(aaSpellCastingMastery))
        {
        case 1:
            PercentManaReduction += 2.5f;
            break;
        case 2:
            PercentManaReduction += 5.0f;
            break;
        case 3:
            PercentManaReduction += 10.0f;
            break;
        }
    }

    int16 focus_redux = GetFocusEffect(focusManaCost, spell_id);

    if(focus_redux > 0)
    {
        PercentManaReduction += zone->random.Real(1, (double)focus_redux);
    }

    cost -= (cost * (PercentManaReduction / 100));

    if(cost < 0)
        cost = 0;

    return cost;
}
示例#13
0
//offensive spell aggro
int32 Mob::CheckAggroAmount(uint16 spell_id, Mob *target, bool isproc)
{
	if (NoDetrimentalSpellAggro(spell_id))
		return 0;

	int32 AggroAmount = 0;
	int32 nonModifiedAggro = 0;
	uint16 slevel = GetLevel();
	bool dispel = false;
	bool on_hatelist = target ? target->CheckAggro(this) : false;
	int proc_cap = RuleI(Aggro, MaxScalingProcAggro);
	int hate_cap = isproc && proc_cap != -1 ? proc_cap : 1200;

	int32 target_hp = target ? target->GetMaxHP() : 18000; // default to max
	int32 default_aggro = 25;
	if (target_hp >= 18000) // max
		default_aggro = hate_cap;
	else if (target_hp >= 390) // min, 390 is the first number with int division that is 26
		default_aggro = target_hp / 15;

	for (int o = 0; o < EFFECT_COUNT; o++) {
		switch (spells[spell_id].effectid[o]) {
			case SE_CurrentHPOnce:
			case SE_CurrentHP: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if(val < 0)
					AggroAmount -= val;
				break;
			}
			case SE_MovementSpeed: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount += default_aggro;
				break;
			}
			case SE_AttackSpeed:
			case SE_AttackSpeed2:
			case SE_AttackSpeed3: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 100)
					AggroAmount += default_aggro;
				break;
			}
			case SE_Stun:
			case SE_Blind:
			case SE_Mez:
			case SE_Charm:
			case SE_Fear:
				AggroAmount += default_aggro;
				break;
			case SE_Root:
				AggroAmount += 10;
				break;
			case SE_ACv2:
			case SE_ArmorClass: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount += default_aggro;
				break;
			}
			case SE_ATK:
			case SE_ResistMagic:
			case SE_ResistFire:
			case SE_ResistCold:
			case SE_ResistPoison:
			case SE_ResistDisease:
			case SE_STR:
			case SE_STA:
			case SE_DEX:
			case SE_AGI:
			case SE_INT:
			case SE_WIS:
			case SE_CHA: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount += 10;
				break;
			}
			case SE_ResistAll: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount += 50;
				break;
			}
			case SE_AllStats: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount += 70;
				break;
			}
			case SE_BardAEDot:
				AggroAmount += 10;
				break;
			case SE_SpinTarget:
			case SE_Amnesia:
			case SE_Silence:
			case SE_Destroy:
				AggroAmount += default_aggro;
				break;
			// unsure -- leave them this for now
			case SE_Harmony:
			case SE_CastingLevel:
			case SE_MeleeMitigation:
			case SE_CriticalHitChance:
			case SE_AvoidMeleeChance:
			case SE_RiposteChance:
			case SE_DodgeChance:
			case SE_ParryChance:
			case SE_DualWieldChance:
			case SE_DoubleAttackChance:
			case SE_MeleeSkillCheck:
			case SE_HitChance:
			case SE_DamageModifier:
			case SE_MinDamageModifier:
			case SE_IncreaseBlockChance:
			case SE_Accuracy:
			case SE_DamageShield:
			case SE_SpellDamageShield:
			case SE_ReverseDS: {
				AggroAmount += slevel * 2;
				break;
			}
			// unsure -- leave them this for now
			case SE_CurrentMana:
			case SE_ManaRegen_v2:
			case SE_ManaPool:
			case SE_CurrentEndurance: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 2;
				break;
			}
			case SE_CancelMagic:
			case SE_DispelDetrimental:
				dispel = true;
				break;
			case SE_ReduceHate:
			case SE_InstantHate:
				nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				break;
		}
	}

	if (IsBardSong(spell_id) && AggroAmount > 40)
		AggroAmount = 40; // bard songs seem to cap to 40 for most of their spells?

	if (dispel && target && target->GetHateAmount(this) < 100)
		AggroAmount += 50;

	if (spells[spell_id].HateAdded > 0) // overrides the hate (ex. tash)
		AggroAmount = spells[spell_id].HateAdded;

	if (GetOwner() && IsPet())
		AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;

	// hate focus ignored on first action for some reason
	if (!on_hatelist && AggroAmount > 0) {
		int HateMod = RuleI(Aggro, SpellAggroMod);
		HateMod += GetFocusEffect(focusSpellHateMod, spell_id);

		AggroAmount = (AggroAmount * HateMod) / 100;
	}

	// initial aggro gets a bonus 100 besides for dispel or hate override
	// We add this 100 in AddToHateList so we need to account for the oddities here
	if (dispel && spells[spell_id].HateAdded > 0 && !on_hatelist)
		AggroAmount -= 100;

	return AggroAmount + spells[spell_id].bonushate + nonModifiedAggro;
}
示例#14
0
int32 Client::GetActSpellDamage(uint16 spell_id, int32 value) {
    // Important variables:
    // value: the actual damage after resists, passed from Mob::SpellEffect
    // modifier: modifier to damage (from spells & focus effects?)
    // ratio: % of the modifier to apply (from AAs & natural bonus?)
    // chance: critital chance %

    int32 modifier = 100;
    int16 spell_dmg = 0;


    //Dunno if this makes sense:
    if (spells[spell_id].resisttype > 0)
        modifier += GetFocusEffect((focusType)(0-spells[spell_id].resisttype), spell_id);


    int tt = spells[spell_id].targettype;
    if (tt == ST_UndeadAE || tt == ST_Undead || tt == ST_Summoned) {
        //undead/summoned spells
        modifier += GetFocusEffect(focusImprovedUndeadDamage, spell_id);
    } else {
        //damage spells.
        modifier += GetFocusEffect(focusImprovedDamage, spell_id);
        modifier += GetFocusEffect(focusSpellEffectiveness, spell_id);
        modifier += GetFocusEffect(focusImprovedDamage2, spell_id);
    }

    // Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
    if ( spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) {
        if (this->GetLevel() > 40)
            value -= (this->GetLevel() - 40) * 20;
    }

    //This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
    if (spell_id == SPELL_IMP_HARM_TOUCH) {  //Improved Harm Touch
        value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch
    }

    // This adds the extra damage for the AA's Consumption of the Soul and Improved Consumption of the Soul, 200 per level to the AA Leech Curse for Shadowknights.
    if (spell_id == SPELL_LEECH_TOUCH) {   //Leech Touch
        value -= GetAA(aaConsumptionoftheSoul) * 200; //Consumption of the Soul
        value -= GetAA(aaImprovedConsumptionofSoul) * 200; //Improved Consumption of the Soul
    }

    //spell crits, dont make sense if cast on self.
    if(tt != ST_Self) {
        // item SpellDmg bonus
        // Formula = SpellDmg * (casttime + recastime) / 7; Cant trigger off spell less than 5 levels below and cant cause more dmg than the spell itself.
        if(this->itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) {
            spell_dmg = this->itembonuses.SpellDmg * (spells[spell_id].cast_time + spells[spell_id].recast_time) / 7000;
            if(spell_dmg > -value)
                spell_dmg = -value;
        }

        // Spell-based SpellDmg adds directly but it restricted by focuses.
        spell_dmg += Additional_SpellDmg(spell_id);

        int chance = RuleI(Spells, BaseCritChance);
        int32 ratio = RuleI(Spells, BaseCritRatio);

        chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
        ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;

        if(GetClass() == WIZARD) {
            if (GetLevel() >= RuleI(Spells, WizCritLevel)) {
                chance += RuleI(Spells, WizCritChance);
                ratio += RuleI(Spells, WizCritRatio);
            }
            if(aabonuses.SpellCritDmgIncrease > 0) // wizards get an additional bonus
                ratio +=  aabonuses.SpellCritDmgIncrease * 1.5; //108%, 115%, 124%, close to Graffe's 207%, 215%, & 225%
        }

        //Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
        if (spell_id == SPELL_IMP_HARM_TOUCH) {
            if ( (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0) )
                chance = 100;
        }

        /*
        //Handled in aa_effects will focus spells from 'spellgroup=99'. (SK life tap from buff procs)
        //If you are using an older spell file table (Pre SOF)...
        //Use SQL optional_EnableSoulAbrasionAA to update your spells table to properly use the effect.
        //If you do not want to update your table then you may want to enable this.
        if(tt == ST_Tap) {
        	if(spells[spell_id].classes[SHADOWKNIGHT-1] >= 254 && spell_id != SPELL_LEECH_TOUCH){
        		if(ratio < 100)	//chance increase and ratio are made up, not confirmed
        			ratio = 100;

        		switch (GetAA(aaSoulAbrasion))
        		{
        		case 1:
        			modifier += 100;
        			break;
        		case 2:
        			modifier += 200;
        			break;
        		case 3:
        			modifier += 300;
        			break;
        		}
        	}
        }
        */

        if (chance > 0) {
            mlog(SPELLS__CRITS, "Attempting spell crit. Spell: %s (%d), Value: %d, Modifier: %d, Chance: %d, Ratio: %d", spells[spell_id].name, spell_id, value, modifier, chance, ratio);
            if(MakeRandomInt(0,100) <= chance) {
                modifier += modifier*ratio/100;
                spell_dmg *= 2;
                mlog(SPELLS__CRITS, "Spell crit successful. Final damage modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
                entity_list.MessageClose(this, false, 100, MT_SpellCrits, "%s delivers a critical blast! (%d)", GetName(), (-value * modifier / 100) + spell_dmg);
            } else
                mlog(SPELLS__CRITS, "Spell crit failed. Final Damage Modifier: %d, Final Damage: %d", modifier, (value * modifier / 100) - spell_dmg);
        }
    }

    return ((value * modifier / 100) - spell_dmg);
}
示例#15
0
文件: aa.cpp 项目: af4t/Server
void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) {

	//It might not be a bad idea to put these into the database, eventually..

	//Dook- swarms and wards

	// do nothing if it's a corpse
	if (targ != nullptr && targ->IsCorpse())
		return;

	// yep, even these need pet power!
	int act_power = 0;

	if (IsClient()) {
		act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
		act_power = CastToClient()->mod_pet_power(act_power, spell_id);
	}

	PetRecord record;
	if (!database.GetPoweredPetEntry(spells[spell_id].teleport_zone, act_power, &record))
	{
		Log(Logs::General, Logs::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
		Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);
		return;
	}

	SwarmPet_Struct pet;
	pet.count = 1;
	pet.duration = 1;

	for (int x = 0; x < MAX_SWARM_PETS; x++)
	{
		if (spells[spell_id].effectid[x] == SE_TemporaryPets)
		{
			pet.count = spells[spell_id].base[x];
			pet.duration = spells[spell_id].max[x];
		}
	}

	pet.duration += GetFocusEffect(focusSwarmPetDuration, spell_id) / 1000;

	pet.npc_id = record.npc_type;

	NPCType *made_npc = nullptr;

	const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id);
	if (npc_type == nullptr) {
		//log write
		Log(Logs::General, Logs::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
		Message(0, "Unable to find pet!");
		return;
	}

	if (name_override != nullptr) {
		//we have to make a custom NPC type for this name change
		made_npc = new NPCType;
		memcpy(made_npc, npc_type, sizeof(NPCType));
		strcpy(made_npc->name, name_override);
		npc_type = made_npc;
	}

	int summon_count = 0;
	summon_count = pet.count;

	if (summon_count > MAX_SWARM_PETS)
		summon_count = MAX_SWARM_PETS;

	static const glm::vec2 swarmPetLocations[MAX_SWARM_PETS] = {
		glm::vec2(5, 5), glm::vec2(-5, 5), glm::vec2(5, -5), glm::vec2(-5, -5),
		glm::vec2(10, 10), glm::vec2(-10, 10), glm::vec2(10, -10), glm::vec2(-10, -10),
		glm::vec2(8, 8), glm::vec2(-8, 8), glm::vec2(8, -8), glm::vec2(-8, -8)
	};

	while (summon_count > 0) {
		int pet_duration = pet.duration;
		if (duration_override > 0)
			pet_duration = duration_override;

		//this is a little messy, but the only way to do it right
		//it would be possible to optimize out this copy for the last pet, but oh well
		NPCType *npc_dup = nullptr;
		if (made_npc != nullptr) {
			npc_dup = new NPCType;
			memcpy(npc_dup, made_npc, sizeof(NPCType));
		}

		NPC* swarm_pet_npc = new NPC(
			(npc_dup != nullptr) ? npc_dup : npc_type,	//make sure we give the NPC the correct data pointer
			0,
			GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
			GravityBehavior::Water);

		if (followme)
			swarm_pet_npc->SetFollowID(GetID());

		if (!swarm_pet_npc->GetSwarmInfo()) {
			auto nSI = new SwarmPet;
			swarm_pet_npc->SetSwarmInfo(nSI);
			swarm_pet_npc->GetSwarmInfo()->duration = new Timer(pet_duration * 1000);
		}
		else {
			swarm_pet_npc->GetSwarmInfo()->duration->Start(pet_duration * 1000);
		}

		swarm_pet_npc->StartSwarmTimer(pet_duration * 1000);

		//removing this prevents the pet from attacking
		swarm_pet_npc->GetSwarmInfo()->owner_id = GetID();

		//give the pets somebody to "love"
		if (targ != nullptr) {
			swarm_pet_npc->AddToHateList(targ, 1000, 1000);
			if (RuleB(Spells, SwarmPetTargetLock) || sticktarg)
				swarm_pet_npc->GetSwarmInfo()->target = targ->GetID();
			else
				swarm_pet_npc->GetSwarmInfo()->target = 0;
		}

		//we allocated a new NPC type object, give the NPC ownership of that memory
		if (npc_dup != nullptr)
			swarm_pet_npc->GiveNPCTypeData(npc_dup);

		entity_list.AddNPC(swarm_pet_npc, true, true);
		summon_count--;
	}

	//the target of these swarm pets will take offense to being cast on...
	if (targ != nullptr)
		targ->AddToHateList(this, 1, 0);

	// The other pointers we make are handled elsewhere.
	delete made_npc;
}
示例#16
0
int32 Client::GetActSpellCost(uint16 spell_id, int32 cost)
{
    // Formula = Unknown exact, based off a random percent chance up to mana cost(after focuses) of the cast spell
    if(this->itembonuses.Clairvoyance && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
    {
        int16 mana_back = this->itembonuses.Clairvoyance * MakeRandomInt(1, 100) / 100;
        // Doesnt generate mana, so best case is a free spell
        if(mana_back > cost)
            mana_back = cost;

        cost -= mana_back;
    }

    // This formula was derived from the following resource:
    // http://www.eqsummoners.com/eq1/specialization-library.html
    // WildcardX
    float PercentManaReduction = 0;
    float SpecializeSkill = GetSpecializeSkillValue(spell_id);
    int SuccessChance = MakeRandomInt(0, 100);

    float bonus = 1.0;
    switch(GetAA(aaSpellCastingMastery))
    {
    case 1:
        bonus += 0.05;
        break;
    case 2:
        bonus += 0.15;
        break;
    case 3:
        bonus += 0.30;
        break;
    }

    bonus += 0.05 * GetAA(aaAdvancedSpellCastingMastery);

    if(SuccessChance <= (SpecializeSkill * 0.3 * bonus))
    {
        PercentManaReduction = 1 + 0.05 * SpecializeSkill;
        switch(GetAA(aaSpellCastingMastery))
        {
        case 1:
            PercentManaReduction += 2.5;
            break;
        case 2:
            PercentManaReduction += 5.0;
            break;
        case 3:
            PercentManaReduction += 10.0;
            break;
        }

        switch(GetAA(aaAdvancedSpellCastingMastery))
        {
        case 1:
            PercentManaReduction += 2.5;
            break;
        case 2:
            PercentManaReduction += 5.0;
            break;
        case 3:
            PercentManaReduction += 10.0;
            break;
        }
    }

    int16 focus_redux = GetFocusEffect(focusManaCost, spell_id);

    if(focus_redux > 0)
    {
        PercentManaReduction += MakeRandomFloat(1, (double)focus_redux);
    }

    cost -= (cost * (PercentManaReduction / 100));

    // Gift of Mana - reduces spell cost to 1 mana
    if(focus_redux >= 100) {
        uint32 buff_max = GetMaxTotalSlots();
        for (int buffSlot = 0; buffSlot < buff_max; buffSlot++) {
            if (buffs[buffSlot].spellid == 0 || buffs[buffSlot].spellid >= SPDAT_RECORDS)
                continue;

            if(IsEffectInSpell(buffs[buffSlot].spellid, SE_ReduceManaCost)) {
                if(CalcFocusEffect(focusManaCost, buffs[buffSlot].spellid, spell_id) == 100)
                    cost = 1;
            }
        }
    }

    if(cost < 0)
        cost = 0;

    return cost;
}
示例#17
0
bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
	// Dont let client waste a reuse timer if they can't use the disc
	if (IsStunned() || IsFeared() || IsMezzed() || IsAmnesiad() || IsPet())
	{
		return(false);
	}

	//make sure we have the spell...
	int r;
	for(r = 0; r < MAX_PP_DISCIPLINES; r++) {
		if(m_pp.disciplines.values[r] == spell_id)
			break;
	}
	if(r == MAX_PP_DISCIPLINES)
		return(false);	//not found.

	//Check the disc timer
	pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].EndurTimerIndex;
	if(!p_timers.Expired(&database, DiscTimer)) {
		/*char val1[20]={0};*/	//unused
		/*char val2[20]={0};*/	//unused
		uint32 remain = p_timers.GetRemainingTime(DiscTimer);
		//Message_StringID(0, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2));
		Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60));
		return(false);
	}

	//make sure we can use it..
	if(!IsValidSpell(spell_id)) {
		Message(13, "This tome contains invalid knowledge.");
		return(false);
	}

	//can we use the spell?
	const SPDat_Spell_Struct &spell = spells[spell_id];
	uint8 level_to_use = spell.classes[GetClass() - 1];
	if(level_to_use == 255) {
		Message(13, "Your class cannot learn from this tome.");
		//should summon them a new one...
		return(false);
	}

	if(level_to_use > GetLevel()) {
		Message_StringID(13, DISC_LEVEL_USE_ERROR);
		//should summon them a new one...
		return(false);
	}

	if(GetEndurance() > spell.EndurCost) {
		SetEndurance(GetEndurance() - spell.EndurCost);
		TryTriggerOnValueAmount(false, false, true);
	} else {
		Message(11, "You are too fatigued to use this skill right now.");
		return(false);
	}

	if(spell.recast_time > 0)
	{
		uint32 reduced_recast = spell.recast_time / 1000;
		reduced_recast -= GetFocusEffect(focusReduceRecastTime, spell_id);
		if(reduced_recast <= 0){
			reduced_recast = 0;
			if (GetPTimers().Enabled((uint32)DiscTimer))
				GetPTimers().Clear(&database, (uint32)DiscTimer);
		}

		if (reduced_recast > 0)
			CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
		else{
			CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
			return true;
		}

		SendDisciplineTimer(spells[spell_id].EndurTimerIndex, reduced_recast);
	}
	else
	{
		CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
	}
	return(true);
}
示例#18
0
int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {

	if (spells[spell_id].targettype == ST_Self)
		return value;

	if (IsNPC())
		value += value*CastToNPC()->GetSpellFocusDMG()/100;

	bool Critical = false;
	int32 value_BaseEffect = 0;
	int chance = 0;

	value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);

	// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
	if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
		value -= (GetLevel() - 40) * 20;

	//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
	if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient()) //Improved Harm Touch
		value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch

		chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level)
		chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
		chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;

	//Crtical Hit Calculation pathway
	if (chance > 0 || (IsClient() && GetClass() == WIZARD && GetLevel() >= RuleI(Spells, WizCritLevel))) {

		 int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.

		//Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
		if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
			 chance = 100;

		if (zone->random.Roll(chance)) {
			Critical = true;
			ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
			ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
		}

		else if ((IsClient() && GetClass() == WIZARD) || (IsMerc() && GetClass() == CASTERDPS)) {
			if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){
				//Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed)
				ratio += zone->random.Int(20,70);
				Critical = true;
			}
		}

		if (IsClient() && GetClass() == WIZARD)
			ratio += RuleI(Spells, WizCritRatio); //Default is zero

		if (Critical){

			value = value_BaseEffect*ratio/100;

			value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;

			value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;

			if (target) {
				value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
				value -= target->GetFcDamageAmtIncoming(this, spell_id);
			}

			value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;

			value -= GetFocusEffect(focusFcDamageAmt, spell_id);

			if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
				value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;

			else if (IsNPC() && CastToNPC()->GetSpellScale())
				value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

			entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
					OTHER_CRIT_BLAST, GetName(), itoa(-value));

			if (IsClient())
				Message_StringID(MT_SpellCrits, YOU_CRIT_BLAST, itoa(-value));

			return value;
		}
	}
	//Non Crtical Hit Calculation pathway
	value = value_BaseEffect;

	value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;

	value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;

	if (target) {
		value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
		value -= target->GetFcDamageAmtIncoming(this, spell_id);
	}

	value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);

	value -= GetFocusEffect(focusFcDamageAmt, spell_id);

	if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
		 value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);

	if (IsNPC() && CastToNPC()->GetSpellScale())
		value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

	return value;
}
示例#19
0
int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {

	if (target == nullptr)
		target = this;

	if (IsNPC())
		value += value*CastToNPC()->GetSpellFocusHeal()/100;

	int32 value_BaseEffect = 0;
	int16 chance = 0;
	int8 modifier = 1;
	bool Critical = false;

	value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);

	value = value_BaseEffect;

	value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);

	// Instant Heals
	if(spells[spell_id].buffduration < 1) {

		chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;

		chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);

		if (spellbonuses.CriticalHealDecay)
			chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);

		if(chance && (zone->random.Roll(chance))) {
			Critical = true;
			modifier = 2; //At present time no critical heal amount modifier SPA exists.
		}

		value *= modifier;
		value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
		value += GetFocusEffect(focusFcHealAmt, spell_id);
		value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);

		if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
			value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;

		value += value*target->GetHealRate(spell_id, this)/100;

		if (IsNPC() && CastToNPC()->GetHealScale())
			value = int(static_cast<float>(value) * CastToNPC()->GetHealScale() / 100.0f);

		if (Critical) {
			entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
					OTHER_CRIT_HEAL, GetName(), itoa(value));

			if (IsClient())
				Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value));
		}

		return value;
	}

	//Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value]
	else {

		chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;

		chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);

		if (spellbonuses.CriticalRegenDecay)
			chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);

		if(chance && zone->random.Roll(chance))
			value *= 2;
	}

	if (IsNPC() && CastToNPC()->GetHealScale())
		value = int(static_cast<float>(value) * CastToNPC()->GetHealScale() / 100.0f);

	return value;
}