mirror of
https://github.com/EQEmu/Server.git
synced 2026-09-05 11:26:35 +00:00
Implemented new table 'npc_spells_effects' and 'npc_spells_effects_entires'.
Implemented new field in 'npc_spell_effects_id' in npc_types. These are used to directly apply spell effect bonuses to NPC's without requirings spells/buffs. Example: Allow an npc to spawn with an innate 50 pt damage shield and a 5% chance to critical hit. Please see the wiki page: http://wiki.eqemulator.org/p?npc_spell_effects_entries for details. *NPC's can now do critical heals / damage spells if bonus is applied from table. Required SQL: utils/sql/git/required/2014_04_27_AISpellEffects.sql Note: 30 examples of spell effects have been included by default in this sql. Edited/removed as needed.
This commit is contained in:
+2
-7
@@ -1901,7 +1901,7 @@ bool NPC::AI_EngagedCastCheck() {
|
||||
AIautocastspell_timer->Disable(); //prevent the timer from going off AGAIN while we are casting.
|
||||
|
||||
mlog(AI__SPELLS, "Engaged autocast check triggered. Trying to cast healing spells then maybe offensive spells.");
|
||||
Shout("KAYEN");
|
||||
|
||||
// try casting a heal or gate
|
||||
if (!AICastSpell(this, 100, SpellType_Heal | SpellType_Escape | SpellType_InCombatBuff)) {
|
||||
// try casting a heal on nearby
|
||||
@@ -2437,12 +2437,9 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
{
|
||||
if (!AI_HasSpellsEffects())
|
||||
return;
|
||||
|
||||
|
||||
|
||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||
{
|
||||
Shout("ApplyAISpellEffects %i %i %i %i", AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, false, 0,-1,
|
||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
}
|
||||
@@ -2456,7 +2453,6 @@ void NPC::AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base, int32 limit
|
||||
|
||||
if(!iSpellEffectID)
|
||||
return;
|
||||
|
||||
|
||||
HasAISpellEffects = true;
|
||||
AISpellsEffects_Struct t;
|
||||
@@ -2465,7 +2461,6 @@ void NPC::AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base, int32 limit
|
||||
t.base = base;
|
||||
t.limit = limit;
|
||||
t.max = max;
|
||||
Shout("AddSpellEffectToNPCList %i %i %i %i", iSpellEffectID,base, limit, max );
|
||||
AIspellsEffects.push_back(t);
|
||||
}
|
||||
|
||||
@@ -2692,7 +2687,7 @@ DBnpcspellseffects_Struct* ZoneDatabase::GetNPCSpellsEffects(uint32 iDBSpellsEff
|
||||
mysql_free_result(result);
|
||||
if (RunQuery(query, MakeAnyLenString(&query, "SELECT spell_effect_id, minlevel, maxlevel,se_base, se_limit, se_max from npc_spells_effects_entries where npc_spells_effects_id=%d ORDER BY minlevel", iDBSpellsEffectsID), errbuf, &result)) {
|
||||
safe_delete_array(query);
|
||||
uint32 tmpSize = sizeof(DBnpcspellseffects_Struct) + (sizeof(DBnpcspellseffects_Struct) * mysql_num_rows(result));
|
||||
uint32 tmpSize = sizeof(DBnpcspellseffects_Struct) + (sizeof(DBnpcspellseffects_entries_Struct) * mysql_num_rows(result));
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID] = (DBnpcspellseffects_Struct*) new uchar[tmpSize];
|
||||
memset(npc_spellseffects_cache[iDBSpellsEffectsID], 0, tmpSize);
|
||||
npc_spellseffects_cache[iDBSpellsEffectsID]->parent_list = tmpparent_list;
|
||||
|
||||
+30
-12
@@ -1158,14 +1158,20 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case SE_SpellEffectResistChance:
|
||||
{
|
||||
for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2)
|
||||
{
|
||||
if(!newbon->SEResist[e] || ((newbon->SEResist[e] = base2) && (newbon->SEResist[e+1] < base1)) ){
|
||||
newbon->SEResist[e] = base2;
|
||||
newbon->SEResist[e+1] = base1;
|
||||
break;
|
||||
if(newbon->SEResist[e+1] && (newbon->SEResist[e] == base2) && (newbon->SEResist[e+1] < base1)){
|
||||
newbon->SEResist[e] = base2; //Spell Effect ID
|
||||
newbon->SEResist[e+1] = base1; //Resist Chance
|
||||
break;
|
||||
}
|
||||
else if (!newbon->SEResist[e+1]){
|
||||
newbon->SEResist[e] = base2; //Spell Effect ID
|
||||
newbon->SEResist[e+1] = base1; //Resist Chance
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1791,10 +1797,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
newbon->MeleeLifetap += spells[spell_id].base[i];
|
||||
|
||||
else if((effect_value < 0) && (newbon->MeleeLifetap > effect_value))
|
||||
newbon->MeleeLifetap = spells[spell_id].base[i];
|
||||
newbon->MeleeLifetap = effect_value;
|
||||
|
||||
else if(newbon->MeleeLifetap < spells[spell_id].base[i])
|
||||
newbon->MeleeLifetap = spells[spell_id].base[i];
|
||||
else if(newbon->MeleeLifetap < effect_value)
|
||||
newbon->MeleeLifetap = effect_value;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2494,10 +2500,14 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
{
|
||||
for(int e = 0; e < MAX_RESISTABLE_EFFECTS*2; e+=2)
|
||||
{
|
||||
if(!newbon->SEResist[e] &&
|
||||
((newbon->SEResist[e] = base2) && (newbon->SEResist[e+1] < effect_value)) ){
|
||||
newbon->SEResist[e] = base2;
|
||||
newbon->SEResist[e+1] = effect_value;
|
||||
if(newbon->SEResist[e+1] && (newbon->SEResist[e] == base2) && (newbon->SEResist[e+1] < effect_value)){
|
||||
newbon->SEResist[e] = base2; //Spell Effect ID
|
||||
newbon->SEResist[e+1] = effect_value; //Resist Chance
|
||||
break;
|
||||
}
|
||||
else if (!newbon->SEResist[e+1]){
|
||||
newbon->SEResist[e] = base2; //Spell Effect ID
|
||||
newbon->SEResist[e+1] = effect_value; //Resist Chance
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2598,7 +2608,15 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_Screech:
|
||||
newbon->Screech = effect_value;
|
||||
break;
|
||||
|
||||
|
||||
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
||||
if (IsAISpellEffect) {
|
||||
|
||||
//Non-Focused Effect to modify incomming spell damage by resist type.
|
||||
case SE_FcSpellVulnerability:
|
||||
ModVulnerability(base2, effect_value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-1
@@ -55,9 +55,36 @@ int32 NPC::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {
|
||||
else
|
||||
value -= target->GetFcDamageAmtIncoming(this, spell_id)/spells[spell_id].buffduration;
|
||||
}
|
||||
|
||||
|
||||
value += dmg*SpellFocusDMG/100;
|
||||
|
||||
if (AI_HasSpellsEffects()){
|
||||
int16 chance = 0;
|
||||
int ratio = 0;
|
||||
|
||||
if (spells[spell_id].buffduration == 0) {
|
||||
|
||||
chance += spellbonuses.CriticalSpellChance + spellbonuses.FrenziedDevastation;
|
||||
|
||||
if (chance && MakeRandomInt(1,100) <= chance){
|
||||
|
||||
ratio += spellbonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncNoStack;
|
||||
value += (value*ratio)/100;
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, OTHER_CRIT_BLAST, GetCleanName(), itoa(-value));
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
chance += spellbonuses.CriticalDoTChance;
|
||||
|
||||
if (chance && MakeRandomInt(1,100) <= chance){
|
||||
|
||||
ratio += spellbonuses.DotCritDmgIncrease;
|
||||
value += (value*ratio)/100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -254,6 +281,21 @@ int32 NPC::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {
|
||||
value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);
|
||||
value += value*target->GetHealRate(spell_id, this)/100;
|
||||
}
|
||||
|
||||
//Allow for critical heal chance if NPC is loading spell effect bonuses.
|
||||
if (AI_HasSpellsEffects()){
|
||||
|
||||
if(spells[spell_id].buffduration < 1) {
|
||||
|
||||
if(spellbonuses.CriticalHealChance && (MakeRandomInt(0,99) < spellbonuses.CriticalHealChance)) {
|
||||
value = value*2;
|
||||
entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, OTHER_CRIT_HEAL, GetCleanName(), itoa(value));
|
||||
}
|
||||
}
|
||||
else if(spellbonuses.CriticalHealOverTime && (MakeRandomInt(0,99) < spellbonuses.CriticalHealOverTime)) {
|
||||
value = value*2;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
+14
-14
@@ -4150,10 +4150,10 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (spells[spell_id].effectid[i] == SE_SpellOnKill2)
|
||||
{
|
||||
if (spells[spell_id].max[i] <= level)
|
||||
if (IsValidSpell(spells[spell_id].base2[i]) && spells[spell_id].max[i] <= level)
|
||||
{
|
||||
if(MakeRandomInt(0,99) < spells[spell_id].base[i])
|
||||
SpellFinished(spells[spell_id].base2[i], this);
|
||||
SpellFinished(spells[spell_id].base2[i], this, 10, 0, -1, spells[spells[spell_id].base2[i]].ResistDiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4166,19 +4166,19 @@ void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)
|
||||
// Allow to check AA, items and buffs in all cases. Base2 = Spell to fire | Base1 = % chance | Base3 = min level
|
||||
for(int i = 0; i < MAX_SPELL_TRIGGER*3; i+=3) {
|
||||
|
||||
if(aabonuses.SpellOnKill[i] && (level >= aabonuses.SpellOnKill[i + 2])) {
|
||||
if(aabonuses.SpellOnKill[i] && IsValidSpell(aabonuses.SpellOnKill[i]) && (level >= aabonuses.SpellOnKill[i + 2])) {
|
||||
if(MakeRandomInt(0, 99) < static_cast<int>(aabonuses.SpellOnKill[i + 1]))
|
||||
SpellFinished(aabonuses.SpellOnKill[i], this);
|
||||
SpellFinished(aabonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
||||
}
|
||||
|
||||
if(itembonuses.SpellOnKill[i] && (level >= itembonuses.SpellOnKill[i + 2])){
|
||||
if(itembonuses.SpellOnKill[i] && IsValidSpell(itembonuses.SpellOnKill[i]) && (level >= itembonuses.SpellOnKill[i + 2])){
|
||||
if(MakeRandomInt(0, 99) < static_cast<int>(itembonuses.SpellOnKill[i + 1]))
|
||||
SpellFinished(itembonuses.SpellOnKill[i], this);
|
||||
SpellFinished(itembonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
||||
}
|
||||
|
||||
if(spellbonuses.SpellOnKill[i] && (level >= spellbonuses.SpellOnKill[i + 2])) {
|
||||
if(spellbonuses.SpellOnKill[i] && IsValidSpell(spellbonuses.SpellOnKill[i]) && (level >= spellbonuses.SpellOnKill[i + 2])) {
|
||||
if(MakeRandomInt(0, 99) < static_cast<int>(spellbonuses.SpellOnKill[i + 1]))
|
||||
SpellFinished(spellbonuses.SpellOnKill[i], this);
|
||||
SpellFinished(spellbonuses.SpellOnKill[i], this, 10, 0, -1, spells[aabonuses.SpellOnKill[i]].ResistDiff);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4193,21 +4193,21 @@ bool Mob::TrySpellOnDeath()
|
||||
return false;
|
||||
|
||||
for(int i = 0; i < MAX_SPELL_TRIGGER*2; i+=2) {
|
||||
if(IsClient() && aabonuses.SpellOnDeath[i]) {
|
||||
if(IsClient() && aabonuses.SpellOnDeath[i] && IsValidSpell(aabonuses.SpellOnDeath[i])) {
|
||||
if(MakeRandomInt(0, 99) < static_cast<int>(aabonuses.SpellOnDeath[i + 1])) {
|
||||
SpellFinished(aabonuses.SpellOnDeath[i], this);
|
||||
SpellFinished(aabonuses.SpellOnDeath[i], this, 10, 0, -1, spells[aabonuses.SpellOnDeath[i]].ResistDiff);
|
||||
}
|
||||
}
|
||||
|
||||
if(itembonuses.SpellOnDeath[i]) {
|
||||
if(itembonuses.SpellOnDeath[i] && IsValidSpell(itembonuses.SpellOnDeath[i])) {
|
||||
if(MakeRandomInt(0, 99) < static_cast<int>(itembonuses.SpellOnDeath[i + 1])) {
|
||||
SpellFinished(itembonuses.SpellOnDeath[i], this);
|
||||
SpellFinished(itembonuses.SpellOnDeath[i], this, 10, 0, -1, spells[itembonuses.SpellOnDeath[i]].ResistDiff);
|
||||
}
|
||||
}
|
||||
|
||||
if(spellbonuses.SpellOnDeath[i]) {
|
||||
if(spellbonuses.SpellOnDeath[i] && IsValidSpell(spellbonuses.SpellOnDeath[i])) {
|
||||
if(MakeRandomInt(0, 99) < static_cast<int>(spellbonuses.SpellOnDeath[i + 1])) {
|
||||
SpellFinished(spellbonuses.SpellOnDeath[i], this);
|
||||
SpellFinished(spellbonuses.SpellOnDeath[i], this, 10, 0, -1, spells[spellbonuses.SpellOnDeath[i]].ResistDiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5675,7 +5675,7 @@ uint16 Mob::GetSpellEffectResistChance(uint16 spell_id)
|
||||
if(!IsValidSpell(spell_id))
|
||||
return 0;
|
||||
|
||||
if (!aabonuses.SEResist[0] && !spellbonuses.SEResist[0] && !itembonuses.SEResist[0])
|
||||
if (!aabonuses.SEResist[1] && !spellbonuses.SEResist[1] && !itembonuses.SEResist[1])
|
||||
return 0;
|
||||
|
||||
uint16 resist_chance = 0;
|
||||
|
||||
Reference in New Issue
Block a user