mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 01:11:29 +00:00
Bard instrument mods should be more consistent with live
Changes: Mods are now saved for in the DB so they are loaded on zone This allows long duration buffs from bards that get mods to keep their mods Ex. Selo's, Symphony of Battle Instrument mods are applied to basically anything that is an instrument skill The only exception to this is discs (ex. Puretone is Singing but always 10) Singing spells from procs (Ex. Storm Blade) that are instrument skills should inherit their buffs instrument mod. Doom effects should also. This isn't implemented yet.
This commit is contained in:
parent
2ef0fc9342
commit
ea5a1dd6f1
@ -1,5 +1,9 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 05/20/2015 ==
|
||||
demonstar55: Bard instrument mods should be more consistent with live. Zoning will keep instrument mod for long duration buffs (selo's)
|
||||
Still need to have procs/doom effects to inherit the instrument mods from their source buff/whatever
|
||||
|
||||
== 05/18/2015 ==
|
||||
KLS: Changed how fishing locates water to hopefully be a bit more accurate at the expense of a bit more cpu power per line cast.
|
||||
|
||||
|
||||
@ -92,3 +92,17 @@ float EQEmu::GetSkillMeleePushForce(SkillUseTypes skill)
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
bool EQEmu::IsBardInstrumentSkill(SkillUseTypes skill)
|
||||
{
|
||||
switch (skill) {
|
||||
case SkillBrassInstruments:
|
||||
case SkillSinging:
|
||||
case SkillStringedInstruments:
|
||||
case SkillWindInstruments:
|
||||
case SkillPercussionInstruments:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -271,6 +271,7 @@ namespace EQEmu {
|
||||
bool IsTradeskill(SkillUseTypes skill);
|
||||
bool IsSpecializedSkill(SkillUseTypes skill);
|
||||
float GetSkillMeleePushForce(SkillUseTypes skill);
|
||||
bool IsBardInstrumentSkill(SkillUseTypes skill);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
|
||||
|
||||
|
||||
#include "../common/eqemu_logsys.h"
|
||||
#include "../common/eqemu_logsys.h"
|
||||
|
||||
#include "classes.h"
|
||||
#include "spdat.h"
|
||||
@ -162,7 +162,7 @@ bool IsCureSpell(uint16 spell_id)
|
||||
bool CureEffect = false;
|
||||
|
||||
for(int i = 0; i < EFFECT_COUNT; i++){
|
||||
if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter
|
||||
if (sp.effectid[i] == SE_DiseaseCounter || sp.effectid[i] == SE_PoisonCounter
|
||||
|| sp.effectid[i] == SE_CurseCounter || sp.effectid[i] == SE_CorruptionCounter)
|
||||
CureEffect = true;
|
||||
}
|
||||
@ -405,7 +405,7 @@ bool IsPartialCapableSpell(uint16 spell_id)
|
||||
{
|
||||
if (spells[spell_id].no_partial_resist)
|
||||
return false;
|
||||
|
||||
|
||||
if (IsPureNukeSpell(spell_id))
|
||||
return true;
|
||||
|
||||
@ -447,7 +447,7 @@ bool IsTGBCompatibleSpell(uint16 spell_id)
|
||||
|
||||
bool IsBardSong(uint16 spell_id)
|
||||
{
|
||||
if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 255)
|
||||
if (IsValidSpell(spell_id) && spells[spell_id].classes[BARD - 1] < 127 && !spells[spell_id].IsDisciplineBuff)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -693,9 +693,9 @@ bool IsCombatSkill(uint16 spell_id)
|
||||
{
|
||||
if (!IsValidSpell(spell_id))
|
||||
return false;
|
||||
|
||||
|
||||
//Check if Discipline
|
||||
if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep)))
|
||||
if ((spells[spell_id].mana == 0 && (spells[spell_id].EndurCost || spells[spell_id].EndurUpkeep)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -1040,7 +1040,7 @@ bool IsCastonFadeDurationSpell(uint16 spell_id)
|
||||
|
||||
bool IsPowerDistModSpell(uint16 spell_id)
|
||||
{
|
||||
if (IsValidSpell(spell_id) &&
|
||||
if (IsValidSpell(spell_id) &&
|
||||
(spells[spell_id].max_dist_mod || spells[spell_id].min_dist_mod) && spells[spell_id].max_dist > spells[spell_id].min_dist)
|
||||
return true;
|
||||
|
||||
|
||||
@ -24,13 +24,13 @@
|
||||
|
||||
#define CURRENT_VERSION "1.1.3"
|
||||
|
||||
/*
|
||||
Everytime a Database SQL is added to Github,
|
||||
/*
|
||||
Everytime a Database SQL is added to Github,
|
||||
increment CURRENT_BINARY_DATABASE_VERSION number and make sure you update the manifest
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
|
||||
*/
|
||||
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9077
|
||||
#define CURRENT_BINARY_DATABASE_VERSION 9078
|
||||
#define COMPILE_DATE __DATE__
|
||||
#define COMPILE_TIME __TIME__
|
||||
#ifndef WIN32
|
||||
|
||||
@ -331,9 +331,10 @@
|
||||
9075|2015_02_02_logsys_packet_logs_with_dump.sql|SELECT * FROM `logsys_categories` WHERE `log_category_description` LIKE 'Packet: Server -> Client With Dump'|empty|
|
||||
9076|2015_02_04_average_coin.sql|SHOW COLUMNS FROM `loottable` WHERE Field = 'avgcoin'|contains|smallint
|
||||
9077|2015_02_12_zone_gravity.sql|SHOW COLUMNS FROM `zone` LIKE 'gravity'|empty|
|
||||
9078|2015_05_20_BuffInstrumentMod.sql|SHOW COLUMNS FROM `character_buffs` LIKE `instrument_mod`|empty|
|
||||
|
||||
# Upgrade conditions:
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
# This won't be needed after this system is implemented, but it is used database that are not
|
||||
# yet using the versioning system to figure out where the database is schema wise to determine
|
||||
# which updates are necessary to run
|
||||
#
|
||||
|
||||
1
utils/sql/git/required/2015_05_20_BuffInstrumentMod.sql
Normal file
1
utils/sql/git/required/2015_05_20_BuffInstrumentMod.sql
Normal file
@ -0,0 +1 @@
|
||||
ALTER TABLE `character_buffs` ADD COLUMN `instrument_mod` int(10) DEFAULT 10 NOT NULL;
|
||||
@ -428,7 +428,7 @@ void Client::AddItemBonuses(const ItemInst *inst, StatBonuses* newbon, bool isAu
|
||||
newbon->DSMitigation += item->DSMitigation;
|
||||
}
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == ET_WornEffect) {// latent effects
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);
|
||||
}
|
||||
|
||||
if (item->Focus.Effect>0 && (item->Focus.Type == ET_Focus)) { // focus effects
|
||||
@ -559,7 +559,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
|
||||
/*
|
||||
Powerful Non-live like option allows developers to add worn effects on items that
|
||||
can stack with other worn effects of the same spell effect type, instead of only taking the highest value.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
Ie Cleave I = 40 pct cleave - So if you equip 3 cleave I items you will have a 120 pct cleave bonus.
|
||||
To enable use RuleI(Spells, AdditiveBonusWornType)
|
||||
Setting value = 2 Will force all live items to automatically be calculated additivily
|
||||
Setting value to anything else will indicate the item 'worntype' that if set to the same, will cause the bonuses to use this calculation
|
||||
@ -579,7 +579,7 @@ void Client::AdditiveWornBonuses(const ItemInst *inst, StatBonuses* newbon, bool
|
||||
|
||||
if(GetLevel() < item->ReqLevel)
|
||||
return;
|
||||
|
||||
|
||||
if (item->Worn.Effect > 0 && item->Worn.Type == RuleI(Spells, AdditiveBonusWornType))
|
||||
ApplySpellsBonuses(item->Worn.Effect, item->Worn.Level, newbon, 0, item->Worn.Type);// Non-live like - Addititive latent effects
|
||||
|
||||
@ -691,7 +691,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
continue;
|
||||
|
||||
Log.Out(Logs::Detail, Logs::AA, "Applying Effect %d from AA %u in slot %d (base1: %d, base2: %d) on %s", effect, aaid, slot, base1, base2, this->GetCleanName());
|
||||
|
||||
|
||||
uint8 focus = IsFocusEffect(0, 0, true,effect);
|
||||
if (focus)
|
||||
{
|
||||
@ -1007,7 +1007,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
case SE_BlockBehind:
|
||||
newbon->BlockBehind += base1;
|
||||
break;
|
||||
|
||||
|
||||
case SE_StrikeThrough:
|
||||
case SE_StrikeThrough2:
|
||||
newbon->StrikeThrough += base1;
|
||||
@ -1313,7 +1313,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
|
||||
case SE_Vampirism:
|
||||
newbon->Vampirism += base1;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_FrenziedDevastation:
|
||||
newbon->FrenziedDevastation += base2;
|
||||
@ -1416,7 +1416,7 @@ void Client::ApplyAABonuses(uint32 aaid, uint32 slots, StatBonuses* newbon)
|
||||
}
|
||||
|
||||
case SE_SkillProcSuccess:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(newbon->SkillProcSuccess[e] && newbon->SkillProcSuccess[e] == aaid)
|
||||
@ -1449,7 +1449,7 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
int buff_count = GetMaxTotalSlots();
|
||||
for(i = 0; i < buff_count; i++) {
|
||||
if(buffs[i].spellid != SPELL_UNKNOWN){
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining,i);
|
||||
ApplySpellsBonuses(buffs[i].spellid, buffs[i].casterlevel, newbon, buffs[i].casterid, 0, buffs[i].ticsremaining, i, buffs[i].instrument_mod);
|
||||
|
||||
if (buffs[i].numhits > 0)
|
||||
Numhits(true);
|
||||
@ -1472,8 +1472,9 @@ void Mob::CalcSpellBonuses(StatBonuses* newbon)
|
||||
if (GetClass() == BARD) newbon->ManaRegen = 0; // Bards do not get mana regen from spells.
|
||||
}
|
||||
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* new_bonus, uint16 casterId, uint8 WornType, uint32 ticsremaining, int buffslot,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses *new_bonus, uint16 casterId,
|
||||
uint8 WornType, uint32 ticsremaining, int buffslot, int instrument_mod,
|
||||
bool IsAISpellEffect, uint16 effect_id, int32 se_base, int32 se_limit, int32 se_max)
|
||||
{
|
||||
int i, effect_value, base2, max, effectid;
|
||||
bool AdditiveWornBonus = false;
|
||||
@ -1509,9 +1510,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
if (WornType && (RuleI(Spells, AdditiveBonusWornType) == WornType))
|
||||
AdditiveWornBonus = true;
|
||||
|
||||
|
||||
effectid = spells[spell_id].effectid[i];
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, caster, ticsremaining);
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, casterlevel, instrument_mod, caster, ticsremaining);
|
||||
base2 = spells[spell_id].base2[i];
|
||||
max = spells[spell_id].max[i];
|
||||
}
|
||||
@ -1620,10 +1621,10 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
if (effect_value > 0 && effect_value > new_bonus->inhibitmelee) {
|
||||
effect_value -= ((effect_value * GetSlowMitigation()/100));
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
if (effect_value > new_bonus->inhibitmelee)
|
||||
new_bonus->inhibitmelee = effect_value;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1839,7 +1840,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
new_bonus->DamageShieldType = GetDamageShieldType(spell_id, max);
|
||||
else
|
||||
new_bonus->DamageShieldType = GetDamageShieldType(spell_id);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2020,7 +2021,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_Vampirism:
|
||||
new_bonus->Vampirism += effect_value;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_AllInstrumentMod:
|
||||
{
|
||||
@ -2263,7 +2264,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
case SE_CriticalSpellChance:
|
||||
{
|
||||
new_bonus->CriticalSpellChance += effect_value;
|
||||
|
||||
|
||||
if (base2 > new_bonus->SpellCritDmgIncNoStack)
|
||||
new_bonus->SpellCritDmgIncNoStack = base2;
|
||||
break;
|
||||
@ -2473,7 +2474,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
case SE_NegateAttacks:
|
||||
{
|
||||
if (!new_bonus->NegateAttacks[0] ||
|
||||
if (!new_bonus->NegateAttacks[0] ||
|
||||
((new_bonus->NegateAttacks[0] && new_bonus->NegateAttacks[2]) && (new_bonus->NegateAttacks[2] < max))){
|
||||
new_bonus->NegateAttacks[0] = 1;
|
||||
new_bonus->NegateAttacks[1] = buffslot;
|
||||
@ -2493,7 +2494,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
case SE_MeleeThresholdGuard:
|
||||
{
|
||||
if (new_bonus->MeleeThresholdGuard[0] < effect_value){
|
||||
@ -2860,17 +2861,17 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
new_bonus->NegateIfCombat = true;
|
||||
break;
|
||||
|
||||
case SE_Screech:
|
||||
case SE_Screech:
|
||||
new_bonus->Screech = effect_value;
|
||||
break;
|
||||
|
||||
case SE_AlterNPCLevel:
|
||||
|
||||
if (IsNPC()){
|
||||
if (!new_bonus->AlterNPCLevel
|
||||
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
||||
if (!new_bonus->AlterNPCLevel
|
||||
|| ((effect_value < 0) && (new_bonus->AlterNPCLevel > effect_value))
|
||||
|| ((effect_value > 0) && (new_bonus->AlterNPCLevel < effect_value))) {
|
||||
|
||||
|
||||
int tmp_lv = GetOrigLevel() + effect_value;
|
||||
if (tmp_lv < 1)
|
||||
tmp_lv = 1;
|
||||
@ -2908,7 +2909,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
new_bonus->BerserkSPA = true;
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case SE_Metabolism:
|
||||
new_bonus->Metabolism += effect_value;
|
||||
break;
|
||||
@ -3009,7 +3010,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
}
|
||||
|
||||
case SE_SkillProc:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(new_bonus->SkillProc[e] && new_bonus->SkillProc[e] == spell_id)
|
||||
@ -3024,7 +3025,7 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
}
|
||||
|
||||
case SE_SkillProcSuccess:{
|
||||
|
||||
|
||||
for(int e = 0; e < MAX_SKILL_PROCS; e++)
|
||||
{
|
||||
if(new_bonus->SkillProcSuccess[e] && new_bonus->SkillProcSuccess[e] == spell_id)
|
||||
@ -3040,9 +3041,9 @@ void Mob::ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* ne
|
||||
|
||||
//Special custom cases for loading effects on to NPC from 'npc_spels_effects' table
|
||||
if (IsAISpellEffect) {
|
||||
|
||||
|
||||
//Non-Focused Effect to modify incoming spell damage by resist type.
|
||||
case SE_FcSpellVulnerability:
|
||||
case SE_FcSpellVulnerability:
|
||||
ModVulnerability(base2, effect_value);
|
||||
break;
|
||||
}
|
||||
@ -4394,7 +4395,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.SlayUndead[0] = effect_value;
|
||||
aabonuses.SlayUndead[1] = effect_value;
|
||||
break;
|
||||
|
||||
|
||||
case SE_DoubleRangedAttack:
|
||||
spellbonuses.DoubleRangedAttack = effect_value;
|
||||
aabonuses.DoubleRangedAttack = effect_value;
|
||||
@ -4414,7 +4415,7 @@ void Mob::NegateSpellsBonuses(uint16 spell_id)
|
||||
aabonuses.ShieldEquipDmgMod[1] = effect_value;
|
||||
itembonuses.ShieldEquipDmgMod[0] = effect_value;
|
||||
itembonuses.ShieldEquipDmgMod[1] = effect_value;
|
||||
break;
|
||||
break;
|
||||
|
||||
case SE_TriggerMeleeThreshold:
|
||||
spellbonuses.TriggerMeleeThreshold = false;
|
||||
|
||||
@ -9092,8 +9092,8 @@ bool Bot::SpellEffect(Mob* caster, uint16 spell_id, float partial) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Bot::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster) {
|
||||
Mob::DoBuffTic(spell_id, slot, ticsremaining, caster_level, caster);
|
||||
void Bot::DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster) {
|
||||
Mob::DoBuffTic(buff, slot, caster);
|
||||
}
|
||||
|
||||
bool Bot::CastSpell(uint16 spell_id, uint16 target_id, uint16 slot, int32 cast_time, int32 mana_cost, uint32* oSpellWillFinish, uint32 item_slot, int16 *resist_adjust) {
|
||||
|
||||
@ -310,7 +310,7 @@ public:
|
||||
virtual int32 GetActSpellDuration(uint16 spell_id, int32 duration);
|
||||
virtual float GetAOERange(uint16 spell_id);
|
||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100);
|
||||
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0);
|
||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||
virtual bool CastSpell(uint16 spell_id, uint16 target_id, uint16 slot = USE_ITEM_SPELL_SLOT, int32 casttime = -1, int32 mana_cost = -1, uint32* oSpellWillFinish = 0, uint32 item_slot = 0xFFFFFFFF, int16 *resist_adjust = nullptr);
|
||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar);
|
||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||
|
||||
@ -1974,101 +1974,87 @@ int32 Client::CalcATK()
|
||||
|
||||
uint32 Mob::GetInstrumentMod(uint16 spell_id) const
|
||||
{
|
||||
if (GetClass() != BARD) {
|
||||
if (GetClass() != BARD || spells[spell_id].IsDisciplineBuff) // Puretone is Singing but doesn't get any mod
|
||||
return 10;
|
||||
}
|
||||
|
||||
uint32 effectmod = 10;
|
||||
int effectmodcap = RuleI(Character, BaseInstrumentSoftCap);
|
||||
//this should never use spell modifiers...
|
||||
//if a spell grants better modifers, they are copied into the item mods
|
||||
//because the spells are supposed to act just like having the intrument.
|
||||
//item mods are in 10ths of percent increases
|
||||
// this should never use spell modifiers...
|
||||
// if a spell grants better modifers, they are copied into the item mods
|
||||
// because the spells are supposed to act just like having the intrument.
|
||||
// item mods are in 10ths of percent increases
|
||||
// clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason
|
||||
// but clickies that are songs (selo's on Composers Greaves) do get AA mod as well
|
||||
switch (spells[spell_id].skill) {
|
||||
case SkillPercussionInstruments:
|
||||
if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillPercussionInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.percussionMod > spellbonuses.percussionMod) {
|
||||
effectmod = itembonuses.percussionMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.percussionMod;
|
||||
}
|
||||
effectmod += aabonuses.percussionMod;
|
||||
break;
|
||||
case SkillStringedInstruments:
|
||||
if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillStringedInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.stringedMod > spellbonuses.stringedMod) {
|
||||
effectmod = itembonuses.stringedMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.stringedMod;
|
||||
}
|
||||
effectmod += aabonuses.stringedMod;
|
||||
break;
|
||||
case SkillWindInstruments:
|
||||
if (itembonuses.windMod == 0 && spellbonuses.windMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillWindInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.windMod > spellbonuses.windMod) {
|
||||
effectmod = itembonuses.windMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.windMod;
|
||||
}
|
||||
effectmod += aabonuses.windMod;
|
||||
break;
|
||||
case SkillBrassInstruments:
|
||||
if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (GetSkill(SkillBrassInstruments) == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.brassMod > spellbonuses.brassMod) {
|
||||
effectmod = itembonuses.brassMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.brassMod;
|
||||
}
|
||||
effectmod += aabonuses.brassMod;
|
||||
break;
|
||||
case SkillSinging:
|
||||
if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0) {
|
||||
effectmod = 10;
|
||||
}
|
||||
else if (itembonuses.singingMod > spellbonuses.singingMod) {
|
||||
effectmod = itembonuses.singingMod;
|
||||
}
|
||||
else {
|
||||
effectmod = spellbonuses.singingMod;
|
||||
}
|
||||
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
|
||||
break;
|
||||
default:
|
||||
case SkillPercussionInstruments:
|
||||
if (itembonuses.percussionMod == 0 && spellbonuses.percussionMod == 0)
|
||||
effectmod = 10;
|
||||
break;
|
||||
else if (GetSkill(SkillPercussionInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.percussionMod > spellbonuses.percussionMod)
|
||||
effectmod = itembonuses.percussionMod;
|
||||
else
|
||||
effectmod = spellbonuses.percussionMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.percussionMod;
|
||||
break;
|
||||
case SkillStringedInstruments:
|
||||
if (itembonuses.stringedMod == 0 && spellbonuses.stringedMod == 0)
|
||||
effectmod = 10;
|
||||
else if (GetSkill(SkillStringedInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.stringedMod > spellbonuses.stringedMod)
|
||||
effectmod = itembonuses.stringedMod;
|
||||
else
|
||||
effectmod = spellbonuses.stringedMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.stringedMod;
|
||||
break;
|
||||
case SkillWindInstruments:
|
||||
if (itembonuses.windMod == 0 && spellbonuses.windMod == 0)
|
||||
effectmod = 10;
|
||||
else if (GetSkill(SkillWindInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.windMod > spellbonuses.windMod)
|
||||
effectmod = itembonuses.windMod;
|
||||
else
|
||||
effectmod = spellbonuses.windMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.windMod;
|
||||
break;
|
||||
case SkillBrassInstruments:
|
||||
if (itembonuses.brassMod == 0 && spellbonuses.brassMod == 0)
|
||||
effectmod = 10;
|
||||
else if (GetSkill(SkillBrassInstruments) == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.brassMod > spellbonuses.brassMod)
|
||||
effectmod = itembonuses.brassMod;
|
||||
else
|
||||
effectmod = spellbonuses.brassMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.brassMod;
|
||||
break;
|
||||
case SkillSinging:
|
||||
if (itembonuses.singingMod == 0 && spellbonuses.singingMod == 0)
|
||||
effectmod = 10;
|
||||
else if (itembonuses.singingMod > spellbonuses.singingMod)
|
||||
effectmod = itembonuses.singingMod;
|
||||
else
|
||||
effectmod = spellbonuses.singingMod;
|
||||
if (IsBardSong(spell_id))
|
||||
effectmod += aabonuses.singingMod + spellbonuses.Amplification;
|
||||
break;
|
||||
default:
|
||||
effectmod = 10;
|
||||
return effectmod;
|
||||
}
|
||||
effectmodcap += aabonuses.songModCap + spellbonuses.songModCap + itembonuses.songModCap;
|
||||
if (effectmod < 10) {
|
||||
if (effectmod < 10)
|
||||
effectmod = 10;
|
||||
}
|
||||
if (effectmod > effectmodcap) {
|
||||
if (effectmod > effectmodcap)
|
||||
effectmod = effectmodcap;
|
||||
}
|
||||
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n",
|
||||
GetName(), spell_id, effectmod, effectmodcap);
|
||||
Log.Out(Logs::Detail, Logs::Spells, "%s::GetInstrumentMod() spell=%d mod=%d modcap=%d\n", GetName(), spell_id,
|
||||
effectmod, effectmodcap);
|
||||
return effectmod;
|
||||
}
|
||||
|
||||
|
||||
@ -1494,7 +1494,7 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
|
||||
for (int i = 0; i < max_slots; i++) {
|
||||
if (buffs[i].spellid != SPELL_UNKNOWN) {
|
||||
m_pp.buffs[i].spellid = buffs[i].spellid;
|
||||
m_pp.buffs[i].bard_modifier = 10;
|
||||
m_pp.buffs[i].bard_modifier = buffs[i].instrument_mod;
|
||||
m_pp.buffs[i].slotid = 2;
|
||||
m_pp.buffs[i].player_id = 0x2211;
|
||||
m_pp.buffs[i].level = buffs[i].casterlevel;
|
||||
|
||||
@ -202,6 +202,7 @@ struct Buffs_Struct {
|
||||
int32 caston_z;
|
||||
int32 ExtraDIChance;
|
||||
int16 RootBreakChance; //Not saved to dbase
|
||||
uint32 instrument_mod;
|
||||
bool persistant_buff;
|
||||
bool client; //True if the caster is a client
|
||||
bool UpdateClient;
|
||||
|
||||
@ -200,7 +200,7 @@ public:
|
||||
bool IsBeneficialAllowed(Mob *target);
|
||||
virtual int GetCasterLevel(uint16 spell_id);
|
||||
void ApplySpellsBonuses(uint16 spell_id, uint8 casterlevel, StatBonuses* newbon, uint16 casterID = 0,
|
||||
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1,
|
||||
uint8 WornType = 0, uint32 ticsremaining = 0, int buffslot = -1, int instrument_mod = 10,
|
||||
bool IsAISpellEffect = false, uint16 effect_id = 0, int32 se_base = 0, int32 se_limit = 0, int32 se_max = 0);
|
||||
void NegateSpellsBonuses(uint16 spell_id);
|
||||
virtual float GetActSpellRange(uint16 spell_id, float range, bool IsBard = false);
|
||||
@ -253,7 +253,7 @@ public:
|
||||
|
||||
//Buff
|
||||
void BuffProcess();
|
||||
virtual void DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster = 0);
|
||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||
void BuffFadeBySpellID(uint16 spell_id);
|
||||
void BuffFadeByEffect(int effectid, int skipslot = -1);
|
||||
void BuffFadeAll();
|
||||
@ -857,7 +857,7 @@ public:
|
||||
virtual uint32 GetAA(uint32 aa_id) const { return(0); }
|
||||
|
||||
uint32 GetInstrumentMod(uint16 spell_id) const;
|
||||
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, Mob *caster = nullptr, int ticsremaining = 0);
|
||||
int CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level = 1, uint32 instrument_mod = 10, Mob *caster = nullptr, int ticsremaining = 0);
|
||||
int CalcSpellEffectValue_formula(int formula, int base, int max, int caster_level, uint16 spell_id, int ticsremaining = 0);
|
||||
virtual int CheckStackConflict(uint16 spellid1, int caster_level1, uint16 spellid2, int caster_level2, Mob* caster1 = nullptr, Mob* caster2 = nullptr, int buffslot = -1);
|
||||
uint32 GetCastedSpellInvSlot() const { return casting_spell_inventory_slot; }
|
||||
|
||||
@ -2565,11 +2565,9 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
||||
if (!AI_HasSpellsEffects())
|
||||
return;
|
||||
|
||||
for(int i=0; i < AIspellsEffects.size(); i++)
|
||||
{
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0,-1,
|
||||
true, AIspellsEffects[i].spelleffectid, AIspellsEffects[i].base, AIspellsEffects[i].limit,AIspellsEffects[i].max);
|
||||
}
|
||||
for (int i = 0; i < AIspellsEffects.size(); i++)
|
||||
ApplySpellsBonuses(0, 0, newbon, 0, 0, 0, -1, 10, true, AIspellsEffects[i].spelleffectid,
|
||||
AIspellsEffects[i].base, AIspellsEffects[i].limit, AIspellsEffects[i].max);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
continue;
|
||||
|
||||
effect = spell.effectid[i];
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster ? caster : this);
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, buffslot > -1 ? buffs[buffslot].instrument_mod : 10, caster ? caster : this);
|
||||
|
||||
if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands))
|
||||
effect_value = GetMaxHP();
|
||||
@ -3029,48 +3029,44 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
return true;
|
||||
}
|
||||
|
||||
int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level, Mob *caster, int ticsremaining)
|
||||
int Mob::CalcSpellEffectValue(uint16 spell_id, int effect_id, int caster_level, uint32 instrument_mod, Mob *caster,
|
||||
int ticsremaining)
|
||||
{
|
||||
int formula, base, max, effect_value;
|
||||
|
||||
if
|
||||
(
|
||||
!IsValidSpell(spell_id) ||
|
||||
effect_id < 0 ||
|
||||
effect_id >= EFFECT_COUNT
|
||||
)
|
||||
if (!IsValidSpell(spell_id) || effect_id < 0 || effect_id >= EFFECT_COUNT)
|
||||
return 0;
|
||||
|
||||
formula = spells[spell_id].formula[effect_id];
|
||||
base = spells[spell_id].base[effect_id];
|
||||
max = spells[spell_id].max[effect_id];
|
||||
|
||||
if(IsBlankSpellEffect(spell_id, effect_id))
|
||||
if (IsBlankSpellEffect(spell_id, effect_id))
|
||||
return 0;
|
||||
|
||||
effect_value = CalcSpellEffectValue_formula(formula, base, max, caster_level, spell_id, ticsremaining);
|
||||
|
||||
if(caster && IsBardSong(spell_id) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_AttackSpeed) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_AttackSpeed2) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_AttackSpeed3) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_Lull) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_ChangeFrenzyRad) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_Harmony) &&
|
||||
(spells[spell_id].effectid[effect_id] != SE_CurrentMana)&&
|
||||
(spells[spell_id].effectid[effect_id] != SE_ManaRegen_v2))
|
||||
{
|
||||
// this doesn't actually need to be a song to get mods, just the right skill
|
||||
if (EQEmu::IsBardInstrumentSkill(spells[spell_id].skill) &&
|
||||
spells[spell_id].effectid[effect_id] != SE_AttackSpeed &&
|
||||
spells[spell_id].effectid[effect_id] != SE_AttackSpeed2 &&
|
||||
spells[spell_id].effectid[effect_id] != SE_AttackSpeed3 &&
|
||||
spells[spell_id].effectid[effect_id] != SE_Lull &&
|
||||
spells[spell_id].effectid[effect_id] != SE_ChangeFrenzyRad &&
|
||||
spells[spell_id].effectid[effect_id] != SE_Harmony &&
|
||||
spells[spell_id].effectid[effect_id] != SE_CurrentMana &&
|
||||
spells[spell_id].effectid[effect_id] != SE_ManaRegen_v2) {
|
||||
|
||||
int oval = effect_value;
|
||||
int mod = caster->GetInstrumentMod(spell_id);
|
||||
mod = ApplySpellEffectiveness(caster, spell_id, mod, true);
|
||||
int mod = ApplySpellEffectiveness(caster, spell_id, instrument_mod, true);
|
||||
effect_value = effect_value * mod / 10;
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Effect value %d altered with bard modifier of %d to yeild %d", oval, mod, effect_value);
|
||||
Log.Out(Logs::Detail, Logs::Spells, "Effect value %d altered with bard modifier of %d to yeild %d",
|
||||
oval, mod, effect_value);
|
||||
}
|
||||
|
||||
effect_value = mod_effect_value(effect_value, spell_id, spells[spell_id].effectid[effect_id], caster);
|
||||
|
||||
return(effect_value);
|
||||
return effect_value;
|
||||
}
|
||||
|
||||
// generic formula calculations
|
||||
@ -3365,7 +3361,7 @@ void Mob::BuffProcess()
|
||||
{
|
||||
if (buffs[buffs_i].spellid != SPELL_UNKNOWN)
|
||||
{
|
||||
DoBuffTic(buffs[buffs_i].spellid, buffs_i, buffs[buffs_i].ticsremaining, buffs[buffs_i].casterlevel, entity_list.GetMob(buffs[buffs_i].casterid));
|
||||
DoBuffTic(buffs[buffs_i], buffs_i, entity_list.GetMob(buffs[buffs_i].casterid));
|
||||
// If the Mob died during DoBuffTic, then the buff we are currently processing will have been removed
|
||||
if(buffs[buffs_i].spellid == SPELL_UNKNOWN)
|
||||
continue;
|
||||
@ -3418,333 +3414,308 @@ void Mob::BuffProcess()
|
||||
}
|
||||
}
|
||||
|
||||
void Mob::DoBuffTic(uint16 spell_id, int slot, uint32 ticsremaining, uint8 caster_level, Mob* caster) {
|
||||
void Mob::DoBuffTic(const Buffs_Struct &buff, int slot, Mob *caster)
|
||||
{
|
||||
int effect, effect_value;
|
||||
|
||||
if(!IsValidSpell(spell_id))
|
||||
if (!IsValidSpell(buff.spellid))
|
||||
return;
|
||||
|
||||
const SPDat_Spell_Struct &spell = spells[spell_id];
|
||||
const SPDat_Spell_Struct &spell = spells[buff.spellid];
|
||||
|
||||
if (spell_id == SPELL_UNKNOWN)
|
||||
return;
|
||||
|
||||
if(IsNPC())
|
||||
{
|
||||
if (IsNPC()) {
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(&ticsremaining);
|
||||
args.push_back(&caster_level);
|
||||
args.push_back(&buff.ticsremaining);
|
||||
args.push_back(&buff.casterlevel);
|
||||
args.push_back(&slot);
|
||||
int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_NPC, CastToNPC(), nullptr, spell_id, caster ? caster->GetID() : 0, &args);
|
||||
if(i != 0) {
|
||||
int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_NPC, CastToNPC(), nullptr, buff.spellid,
|
||||
caster ? caster->GetID() : 0, &args);
|
||||
if (i != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::vector<EQEmu::Any> args;
|
||||
args.push_back(&ticsremaining);
|
||||
args.push_back(&caster_level);
|
||||
args.push_back(&buff.ticsremaining);
|
||||
args.push_back(&buff.casterlevel);
|
||||
args.push_back(&slot);
|
||||
int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_CLIENT, nullptr, CastToClient(), spell_id, caster ? caster->GetID() : 0, &args);
|
||||
if(i != 0) {
|
||||
int i = parse->EventSpell(EVENT_SPELL_BUFF_TIC_CLIENT, nullptr, CastToClient(), buff.spellid,
|
||||
caster ? caster->GetID() : 0, &args);
|
||||
if (i != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for non buff spell effects to fade
|
||||
// AE melee effects
|
||||
if(IsClient())
|
||||
if (IsClient())
|
||||
CastToClient()->CheckAAEffect(aaEffectRampage);
|
||||
|
||||
for (int i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
if(IsBlankSpellEffect(spell_id, i))
|
||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||
if (IsBlankSpellEffect(buff.spellid, i))
|
||||
continue;
|
||||
|
||||
effect = spell.effectid[i];
|
||||
//I copied the calculation into each case which needed it instead of
|
||||
//doing it every time up here, since most buff effects dont need it
|
||||
// I copied the calculation into each case which needed it instead of
|
||||
// doing it every time up here, since most buff effects dont need it
|
||||
|
||||
switch(effect)
|
||||
{
|
||||
case SE_CurrentHP:
|
||||
{
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster, ticsremaining);
|
||||
//Handle client cast DOTs here.
|
||||
if (caster && effect_value < 0){
|
||||
switch (effect) {
|
||||
case SE_CurrentHP: {
|
||||
effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod,
|
||||
caster, buff.ticsremaining);
|
||||
// Handle client cast DOTs here.
|
||||
if (caster && effect_value < 0) {
|
||||
|
||||
if (IsDetrimentalSpell(spell_id)){
|
||||
if (caster->IsClient()){
|
||||
if (!caster->CastToClient()->GetFeigned())
|
||||
AddToHateList(caster, -effect_value);
|
||||
}
|
||||
else if (!IsClient()) //Allow NPC's to generate hate if casted on other NPC's.
|
||||
if (IsDetrimentalSpell(buff.spellid)) {
|
||||
if (caster->IsClient()) {
|
||||
if (!caster->CastToClient()->GetFeigned())
|
||||
AddToHateList(caster, -effect_value);
|
||||
}
|
||||
|
||||
effect_value = caster->GetActDoTDamage(spell_id, effect_value, this);
|
||||
|
||||
caster->ResourceTap(-effect_value, spell_id);
|
||||
effect_value = -effect_value;
|
||||
Damage(caster, effect_value, spell_id, spell.skill, false, i, true);
|
||||
} else if(effect_value > 0) {
|
||||
// Regen spell...
|
||||
// handled with bonuses
|
||||
} else if (!IsClient()) // Allow NPC's to generate hate if casted on other
|
||||
// NPC's.
|
||||
AddToHateList(caster, -effect_value);
|
||||
}
|
||||
break;
|
||||
|
||||
effect_value = caster->GetActDoTDamage(buff.spellid, effect_value, this);
|
||||
|
||||
caster->ResourceTap(-effect_value, buff.spellid);
|
||||
effect_value = -effect_value;
|
||||
Damage(caster, effect_value, buff.spellid, spell.skill, false, i, true);
|
||||
} else if (effect_value > 0) {
|
||||
// Regen spell...
|
||||
// handled with bonuses
|
||||
}
|
||||
case SE_HealOverTime:
|
||||
{
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level);
|
||||
if(caster)
|
||||
effect_value = caster->GetActSpellHealing(spell_id, effect_value);
|
||||
break;
|
||||
}
|
||||
case SE_HealOverTime: {
|
||||
effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod);
|
||||
if (caster)
|
||||
effect_value = caster->GetActSpellHealing(buff.spellid, effect_value);
|
||||
|
||||
HealDamage(effect_value, caster, spell_id);
|
||||
//healing aggro would go here; removed for now
|
||||
HealDamage(effect_value, caster, buff.spellid);
|
||||
// healing aggro would go here; removed for now
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_CurrentEndurance: {
|
||||
// Handled with bonuses
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_BardAEDot: {
|
||||
effect_value =
|
||||
CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod, caster);
|
||||
|
||||
if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable ||
|
||||
/*effect_value > 0 ||*/ DivineAura())
|
||||
break;
|
||||
|
||||
if (effect_value < 0) {
|
||||
effect_value = -effect_value;
|
||||
if (caster) {
|
||||
if (caster->IsClient() && !caster->CastToClient()->GetFeigned()) {
|
||||
AddToHateList(caster, effect_value);
|
||||
} else if (!caster->IsClient())
|
||||
AddToHateList(caster, effect_value);
|
||||
}
|
||||
Damage(caster, effect_value, buff.spellid, spell.skill, false, i, true);
|
||||
} else if (effect_value > 0) {
|
||||
// healing spell...
|
||||
HealDamage(effect_value, caster);
|
||||
// healing aggro would go here; removed for now
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_CurrentEndurance: {
|
||||
// Handled with bonuses
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_BardAEDot:
|
||||
{
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level, caster);
|
||||
|
||||
if ((!RuleB(Spells, PreNerfBardAEDoT) && IsMoving()) || invulnerable || /*effect_value > 0 ||*/ DivineAura())
|
||||
break;
|
||||
|
||||
if(effect_value < 0) {
|
||||
effect_value = -effect_value;
|
||||
if(caster){
|
||||
if(caster->IsClient() && !caster->CastToClient()->GetFeigned()){
|
||||
case SE_Hate: {
|
||||
effect_value = CalcSpellEffectValue(buff.spellid, i, buff.casterlevel, buff.instrument_mod);
|
||||
if (caster) {
|
||||
if (effect_value > 0) {
|
||||
if (caster) {
|
||||
if (caster->IsClient() && !caster->CastToClient()->GetFeigned()) {
|
||||
AddToHateList(caster, effect_value);
|
||||
}
|
||||
else if(!caster->IsClient())
|
||||
} else if (!caster->IsClient())
|
||||
AddToHateList(caster, effect_value);
|
||||
}
|
||||
Damage(caster, effect_value, spell_id, spell.skill, false, i, true);
|
||||
} else if(effect_value > 0) {
|
||||
//healing spell...
|
||||
HealDamage(effect_value, caster);
|
||||
//healing aggro would go here; removed for now
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Hate:{
|
||||
effect_value = CalcSpellEffectValue(spell_id, i, caster_level);
|
||||
if(caster){
|
||||
if(effect_value > 0){
|
||||
if(caster){
|
||||
if(caster->IsClient() && !caster->CastToClient()->GetFeigned()){
|
||||
AddToHateList(caster, effect_value);
|
||||
}
|
||||
else if(!caster->IsClient())
|
||||
AddToHateList(caster, effect_value);
|
||||
}
|
||||
}else{
|
||||
int32 newhate = GetHateAmount(caster) + effect_value;
|
||||
if (newhate < 1) {
|
||||
SetHateAmountOnEnt(caster,1);
|
||||
} else {
|
||||
SetHateAmountOnEnt(caster,newhate);
|
||||
}
|
||||
} else {
|
||||
int32 newhate = GetHateAmount(caster) + effect_value;
|
||||
if (newhate < 1) {
|
||||
SetHateAmountOnEnt(caster, 1);
|
||||
} else {
|
||||
SetHateAmountOnEnt(caster, newhate);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_WipeHateList: {
|
||||
if (IsMezSpell(buff.spellid))
|
||||
break;
|
||||
|
||||
int wipechance = spells[buff.spellid].base[i];
|
||||
int bonus = 0;
|
||||
|
||||
if (caster) {
|
||||
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
|
||||
caster->itembonuses.IncreaseChanceMemwipe +
|
||||
caster->aabonuses.IncreaseChanceMemwipe;
|
||||
}
|
||||
|
||||
case SE_WipeHateList:
|
||||
{
|
||||
if (IsMezSpell(spell_id))
|
||||
wipechance += wipechance * bonus / 100;
|
||||
|
||||
if (zone->random.Roll(wipechance)) {
|
||||
if (IsAIControlled()) {
|
||||
WipeHateList();
|
||||
}
|
||||
Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so "
|
||||
"clear a moment ago...");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Charm: {
|
||||
if (!caster || !PassCharismaCheck(caster, buff.spellid)) {
|
||||
BuffFadeByEffect(SE_Charm);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Root: {
|
||||
/* Root formula derived from extensive personal live parses - Kayen
|
||||
ROOT has a 70% chance to do a resist check to break.
|
||||
*/
|
||||
|
||||
if (zone->random.Roll(RuleI(Spells, RootBreakCheckChance))) {
|
||||
float resist_check =
|
||||
ResistSpell(spells[buff.spellid].resisttype, buff.spellid, caster, 0, 0, 0, 0, true);
|
||||
|
||||
if (resist_check == 100)
|
||||
break;
|
||||
|
||||
int wipechance = spells[spell_id].base[i];
|
||||
int bonus = 0;
|
||||
|
||||
if (caster){
|
||||
bonus = caster->spellbonuses.IncreaseChanceMemwipe +
|
||||
caster->itembonuses.IncreaseChanceMemwipe +
|
||||
caster->aabonuses.IncreaseChanceMemwipe;
|
||||
}
|
||||
|
||||
wipechance += wipechance*bonus/100;
|
||||
|
||||
if(zone->random.Roll(wipechance))
|
||||
{
|
||||
if(IsAIControlled())
|
||||
{
|
||||
WipeHateList();
|
||||
}
|
||||
Message(13, "Your mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago...");
|
||||
}
|
||||
break;
|
||||
else if (!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot);
|
||||
}
|
||||
|
||||
case SE_Charm: {
|
||||
if (!caster || !PassCharismaCheck(caster, spell_id)) {
|
||||
BuffFadeByEffect(SE_Charm);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case SE_Fear: {
|
||||
if (zone->random.Roll(RuleI(Spells, FearBreakCheckChance))) {
|
||||
float resist_check = ResistSpell(spells[buff.spellid].resisttype, buff.spellid, caster);
|
||||
|
||||
case SE_Root: {
|
||||
/* Root formula derived from extensive personal live parses - Kayen
|
||||
ROOT has a 70% chance to do a resist check to break.
|
||||
*/
|
||||
|
||||
if (zone->random.Roll(RuleI(Spells, RootBreakCheckChance))) {
|
||||
float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster, 0,0,0,0,true);
|
||||
|
||||
if(resist_check == 100)
|
||||
break;
|
||||
else
|
||||
if(!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Fear:
|
||||
{
|
||||
if (zone->random.Roll(RuleI(Spells, FearBreakCheckChance))) {
|
||||
float resist_check = ResistSpell(spells[spell_id].resisttype, spell_id, caster);
|
||||
|
||||
if(resist_check == 100)
|
||||
break;
|
||||
else
|
||||
if(!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_Hunger: {
|
||||
// this procedure gets called 7 times for every once that the stamina update occurs so we add 1/7 of the subtraction.
|
||||
// It's far from perfect, but works without any unnecessary buff checks to bog down the server.
|
||||
if(IsClient()) {
|
||||
CastToClient()->m_pp.hunger_level += 5;
|
||||
CastToClient()->m_pp.thirst_level += 5;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_Invisibility:
|
||||
case SE_InvisVsAnimals:
|
||||
case SE_InvisVsUndead:
|
||||
{
|
||||
if(ticsremaining > 3)
|
||||
{
|
||||
if(!IsBardSong(spell_id))
|
||||
{
|
||||
double break_chance = 2.0;
|
||||
if(caster)
|
||||
{
|
||||
break_chance -= (2 * (((double)caster->GetSkill(SkillDivination) + ((double)caster->GetLevel() * 3.0)) / 650.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
break_chance -= (2 * (((double)GetSkill(SkillDivination) + ((double)GetLevel() * 3.0)) / 650.0));
|
||||
}
|
||||
|
||||
if(zone->random.Real(0.0, 100.0) < break_chance)
|
||||
{
|
||||
BuffModifyDurationBySpellID(spell_id, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case SE_Invisibility2:
|
||||
case SE_InvisVsUndead2:
|
||||
{
|
||||
if(ticsremaining <= 3 && ticsremaining > 1)
|
||||
{
|
||||
Message_StringID(MT_Spells, INVIS_BEGIN_BREAK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_InterruptCasting:
|
||||
{
|
||||
if(IsCasting())
|
||||
{
|
||||
if(zone->random.Roll(spells[spell_id].base[i]))
|
||||
{
|
||||
InterruptSpell();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// These effects always trigger when they fade.
|
||||
case SE_CastOnFadeEffect:
|
||||
case SE_CastOnFadeEffectNPC:
|
||||
case SE_CastOnFadeEffectAlways:
|
||||
{
|
||||
if (ticsremaining == 1)
|
||||
{
|
||||
SpellOnTarget(spells[spell_id].base[i], this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_LocateCorpse:
|
||||
{
|
||||
// This is handled by the client prior to SoD.
|
||||
|
||||
if(IsClient() && (CastToClient()->GetClientVersionBit() & BIT_SoDAndLater))
|
||||
CastToClient()->LocateCorpse();
|
||||
}
|
||||
case SE_TotalHP:
|
||||
{
|
||||
if (spell.formula[i] > 1000 && spell.formula[i] < 1999)
|
||||
{
|
||||
// These formulas can affect Max HP each tick
|
||||
// Maybe there is a more efficient way to recalculate this for just Max HP each tic...
|
||||
//CalcBonuses();
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcMaxHP();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DistanceRemoval:
|
||||
{
|
||||
if (spellbonuses.DistanceRemoval){
|
||||
|
||||
int distance = ((int(GetX()) - buffs[slot].caston_x) * (int(GetX()) - buffs[slot].caston_x)) +
|
||||
((int(GetY()) - buffs[slot].caston_y) * (int(GetY()) - buffs[slot].caston_y)) +
|
||||
((int(GetZ()) - buffs[slot].caston_z) * (int(GetZ()) - buffs[slot].caston_z));
|
||||
|
||||
if (distance > (spells[spell_id].base[i] * spells[spell_id].base[i])){
|
||||
|
||||
if(!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot , true);
|
||||
}
|
||||
if (resist_check == 100)
|
||||
break;
|
||||
}
|
||||
else if (!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot);
|
||||
}
|
||||
|
||||
case SE_AddHateOverTimePct:
|
||||
{
|
||||
if (IsNPC()){
|
||||
uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
|
||||
if (new_hate <= 0)
|
||||
new_hate = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
CastToNPC()->SetHateAmountOnEnt(caster, new_hate);
|
||||
case SE_Hunger: {
|
||||
// this procedure gets called 7 times for every once that the stamina update occurs so we add
|
||||
// 1/7 of the subtraction.
|
||||
// It's far from perfect, but works without any unnecessary buff checks to bog down the server.
|
||||
if (IsClient()) {
|
||||
CastToClient()->m_pp.hunger_level += 5;
|
||||
CastToClient()->m_pp.thirst_level += 5;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_Invisibility:
|
||||
case SE_InvisVsAnimals:
|
||||
case SE_InvisVsUndead: {
|
||||
if (buff.ticsremaining > 3) {
|
||||
if (!IsBardSong(buff.spellid)) {
|
||||
double break_chance = 2.0;
|
||||
if (caster) {
|
||||
break_chance -= (2 * (((double)caster->GetSkill(SkillDivination) +
|
||||
((double)caster->GetLevel() * 3.0)) /
|
||||
650.0));
|
||||
} else {
|
||||
break_chance -=
|
||||
(2 *
|
||||
(((double)GetSkill(SkillDivination) + ((double)GetLevel() * 3.0)) /
|
||||
650.0));
|
||||
}
|
||||
|
||||
if (zone->random.Real(0.0, 100.0) < break_chance) {
|
||||
BuffModifyDurationBySpellID(buff.spellid, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case SE_Invisibility2:
|
||||
case SE_InvisVsUndead2: {
|
||||
if (buff.ticsremaining <= 3 && buff.ticsremaining > 1) {
|
||||
Message_StringID(MT_Spells, INVIS_BEGIN_BREAK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_InterruptCasting: {
|
||||
if (IsCasting()) {
|
||||
if (zone->random.Roll(spells[buff.spellid].base[i])) {
|
||||
InterruptSpell();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// These effects always trigger when they fade.
|
||||
case SE_CastOnFadeEffect:
|
||||
case SE_CastOnFadeEffectNPC:
|
||||
case SE_CastOnFadeEffectAlways: {
|
||||
if (buff.ticsremaining == 1) {
|
||||
SpellOnTarget(spells[buff.spellid].base[i], this);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SE_LocateCorpse: {
|
||||
// This is handled by the client prior to SoD.
|
||||
|
||||
if (IsClient() && (CastToClient()->GetClientVersionBit() & BIT_SoDAndLater))
|
||||
CastToClient()->LocateCorpse();
|
||||
}
|
||||
case SE_TotalHP: {
|
||||
if (spell.formula[i] > 1000 && spell.formula[i] < 1999) {
|
||||
// These formulas can affect Max HP each tick
|
||||
// Maybe there is a more efficient way to recalculate this for just Max HP each tic...
|
||||
// CalcBonuses();
|
||||
CalcSpellBonuses(&spellbonuses);
|
||||
CalcMaxHP();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SE_DistanceRemoval: {
|
||||
if (spellbonuses.DistanceRemoval) {
|
||||
|
||||
int distance =
|
||||
((int(GetX()) - buff.caston_x) * (int(GetX()) - buff.caston_x)) +
|
||||
((int(GetY()) - buff.caston_y) * (int(GetY()) - buff.caston_y)) +
|
||||
((int(GetZ()) - buff.caston_z) * (int(GetZ()) - buff.caston_z));
|
||||
|
||||
if (distance > (spells[buff.spellid].base[i] * spells[buff.spellid].base[i])) {
|
||||
|
||||
if (!TryFadeEffect(slot))
|
||||
BuffFadeBySlot(slot, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case SE_AddHateOverTimePct: {
|
||||
if (IsNPC()) {
|
||||
uint32 new_hate = CastToNPC()->GetHateAmount(caster) * (100 + spell.base[i]) / 100;
|
||||
if (new_hate <= 0)
|
||||
new_hate = 1;
|
||||
|
||||
default:
|
||||
{
|
||||
// do we need to do anyting here?
|
||||
CastToNPC()->SetHateAmountOnEnt(caster, new_hate);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
// do we need to do anyting here?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3189,6 +3189,7 @@ int Mob::AddBuff(Mob *caster, uint16 spell_id, int duration, int32 level_overrid
|
||||
buffs[emptyslot].dot_rune = 0;
|
||||
buffs[emptyslot].ExtraDIChance = 0;
|
||||
buffs[emptyslot].RootBreakChance = 0;
|
||||
buffs[emptyslot].instrument_mod = caster ? caster->GetInstrumentMod(spell_id) : 10;
|
||||
|
||||
if (level_override > 0) {
|
||||
buffs[emptyslot].UpdateClient = true;
|
||||
|
||||
150
zone/zonedb.cpp
150
zone/zonedb.cpp
@ -196,7 +196,7 @@ bool ZoneDatabase::GetZoneCFG(uint32 zoneid, uint16 instance_id, NewZone_Struct
|
||||
zone_data->time_type = atoi(row[30]);
|
||||
|
||||
//not in the DB yet:
|
||||
zone_data->gravity = atof(row[56]);
|
||||
zone_data->gravity = atof(row[56]);
|
||||
Log.Out(Logs::General, Logs::Debug, "Zone Gravity is %f", zone_data->gravity);
|
||||
allow_mercs = true;
|
||||
|
||||
@ -248,7 +248,7 @@ void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint3
|
||||
|
||||
if(time_left == 0) {
|
||||
std::string query = StringFormat("DELETE FROM `respawn_times` WHERE `id` = %u AND `instance_id` = %u", spawn2_id, instance_id);
|
||||
QueryDatabase(query);
|
||||
QueryDatabase(query);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -258,14 +258,14 @@ void ZoneDatabase::UpdateRespawnTime(uint32 spawn2_id, uint16 instance_id, uint3
|
||||
"start, "
|
||||
"duration, "
|
||||
"instance_id) "
|
||||
"VALUES "
|
||||
"VALUES "
|
||||
"(%u, "
|
||||
"%u, "
|
||||
"%u, "
|
||||
"%u)",
|
||||
spawn2_id,
|
||||
spawn2_id,
|
||||
current_time,
|
||||
time_left,
|
||||
time_left,
|
||||
instance_id
|
||||
);
|
||||
QueryDatabase(query);
|
||||
@ -1054,8 +1054,8 @@ bool ZoneDatabase::LoadCharacterLanguages(uint32 character_id, PlayerProfile_Str
|
||||
for (i = 0; i < MAX_PP_LANGUAGE; ++i)
|
||||
pp->languages[i] = 0;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
if (i < MAX_PP_LANGUAGE){
|
||||
pp->languages[i] = atoi(row[1]);
|
||||
}
|
||||
@ -1102,14 +1102,14 @@ bool ZoneDatabase::LoadCharacterSkills(uint32 character_id, PlayerProfile_Struct
|
||||
"FROM "
|
||||
"`character_skills` "
|
||||
"WHERE `id` = %u ORDER BY `skill_id`", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
auto results = database.QueryDatabase(query);
|
||||
int i = 0;
|
||||
/* Initialize Skill */
|
||||
for (i = 0; i < MAX_PP_SKILL; ++i)
|
||||
pp->skills[i] = 0;
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
i = atoi(row[0]);
|
||||
if (i < MAX_PP_SKILL)
|
||||
pp->skills[i] = atoi(row[1]);
|
||||
}
|
||||
@ -1259,7 +1259,7 @@ bool ZoneDatabase::LoadCharacterPotions(uint32 character_id, PlayerProfile_Struc
|
||||
|
||||
bool ZoneDatabase::LoadCharacterBindPoint(uint32 character_id, PlayerProfile_Struct* pp){
|
||||
std::string query = StringFormat("SELECT `zone_id`, `instance_id`, `x`, `y`, `z`, `heading`, `is_home` FROM `character_bind` WHERE `id` = %u LIMIT 2", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
auto results = database.QueryDatabase(query);
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
|
||||
@ -1705,8 +1705,8 @@ bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Stru
|
||||
pp->careerRadCrystals,
|
||||
pp->currentEbonCrystals,
|
||||
pp->careerEbonCrystals);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log.Out(Logs::General, Logs::None, "Saving Currency for character ID: %i, done", character_id);
|
||||
auto results = database.QueryDatabase(query);
|
||||
Log.Out(Logs::General, Logs::None, "Saving Currency for character ID: %i, done", character_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1802,7 +1802,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
||||
std::string where_condition = "";
|
||||
|
||||
if (bulk_load){
|
||||
Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load");
|
||||
Log.Out(Logs::General, Logs::Debug, "Performing bulk NPC Types load");
|
||||
where_condition = StringFormat(
|
||||
"INNER JOIN spawnentry ON npc_types.id = spawnentry.npcID "
|
||||
"INNER JOIN spawn2 ON spawnentry.spawngroupID = spawn2.spawngroupID "
|
||||
@ -1910,7 +1910,7 @@ const NPCType* ZoneDatabase::LoadNPCTypesData(uint32 npc_type_id, bool bulk_load
|
||||
"npc_types.handtexture, "
|
||||
"npc_types.legtexture, "
|
||||
"npc_types.feettexture "
|
||||
"FROM npc_types %s",
|
||||
"FROM npc_types %s",
|
||||
where_condition.c_str()
|
||||
);
|
||||
|
||||
@ -2369,7 +2369,7 @@ bool ZoneDatabase::LoadCurrentMerc(Client *client) {
|
||||
|
||||
if(!results.Success())
|
||||
return false;
|
||||
|
||||
|
||||
if(results.RowCount() == 0)
|
||||
return false;
|
||||
|
||||
@ -2980,45 +2980,48 @@ void ZoneDatabase::SaveBuffs(Client *client) {
|
||||
|
||||
query = StringFormat("INSERT INTO `character_buffs` (character_id, slot_id, spell_id, "
|
||||
"caster_level, caster_name, ticsremaining, counters, numhits, melee_rune, "
|
||||
"magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance) "
|
||||
"magic_rune, persistent, dot_rune, caston_x, caston_y, caston_z, ExtraDIChance, "
|
||||
"instrument_mod) "
|
||||
"VALUES('%u', '%u', '%u', '%u', '%s', '%u', '%u', '%u', '%u', '%u', '%u', '%u', "
|
||||
"'%i', '%i', '%i', '%i')", client->CharacterID(), index, buffs[index].spellid,
|
||||
"'%i', '%i', '%i', '%i', '%i')", client->CharacterID(), index, buffs[index].spellid,
|
||||
buffs[index].casterlevel, buffs[index].caster_name, buffs[index].ticsremaining,
|
||||
buffs[index].counters, buffs[index].numhits, buffs[index].melee_rune,
|
||||
buffs[index].magic_rune, buffs[index].persistant_buff, buffs[index].dot_rune,
|
||||
buffs[index].caston_x, buffs[index].caston_y, buffs[index].caston_z,
|
||||
buffs[index].ExtraDIChance);
|
||||
buffs[index].ExtraDIChance, buffs[index].instrument_mod);
|
||||
QueryDatabase(query);
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneDatabase::LoadBuffs(Client *client) {
|
||||
void ZoneDatabase::LoadBuffs(Client *client)
|
||||
{
|
||||
|
||||
Buffs_Struct *buffs = client->GetBuffs();
|
||||
uint32 max_slots = client->GetMaxBuffSlots();
|
||||
|
||||
for(int index = 0; index < max_slots; ++index)
|
||||
for (int index = 0; index < max_slots; ++index)
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
|
||||
std::string query = StringFormat("SELECT spell_id, slot_id, caster_level, caster_name, ticsremaining, "
|
||||
"counters, numhits, melee_rune, magic_rune, persistent, dot_rune, "
|
||||
"caston_x, caston_y, caston_z, ExtraDIChance "
|
||||
"FROM `character_buffs` WHERE `character_id` = '%u'", client->CharacterID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
"counters, numhits, melee_rune, magic_rune, persistent, dot_rune, "
|
||||
"caston_x, caston_y, caston_z, ExtraDIChance, instrument_mod "
|
||||
"FROM `character_buffs` WHERE `character_id` = '%u'",
|
||||
client->CharacterID());
|
||||
auto results = QueryDatabase(query);
|
||||
if (!results.Success()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 slot_id = atoul(row[1]);
|
||||
if(slot_id >= client->GetMaxBuffSlots())
|
||||
for (auto row = results.begin(); row != results.end(); ++row) {
|
||||
uint32 slot_id = atoul(row[1]);
|
||||
if (slot_id >= client->GetMaxBuffSlots())
|
||||
continue;
|
||||
|
||||
uint32 spell_id = atoul(row[0]);
|
||||
if(!IsValidSpell(spell_id))
|
||||
continue;
|
||||
uint32 spell_id = atoul(row[0]);
|
||||
if (!IsValidSpell(spell_id))
|
||||
continue;
|
||||
|
||||
Client *caster = entity_list.GetClientByName(row[3]);
|
||||
Client *caster = entity_list.GetClientByName(row[3]);
|
||||
uint32 caster_level = atoi(row[2]);
|
||||
uint32 ticsremaining = atoul(row[4]);
|
||||
uint32 counters = atoul(row[5]);
|
||||
@ -3031,53 +3034,54 @@ void ZoneDatabase::LoadBuffs(Client *client) {
|
||||
int32 caston_y = atoul(row[12]);
|
||||
int32 caston_z = atoul(row[13]);
|
||||
int32 ExtraDIChance = atoul(row[14]);
|
||||
uint32 instrument_mod = atoul(row[15]);
|
||||
|
||||
buffs[slot_id].spellid = spell_id;
|
||||
buffs[slot_id].casterlevel = caster_level;
|
||||
buffs[slot_id].casterlevel = caster_level;
|
||||
|
||||
if(caster) {
|
||||
buffs[slot_id].casterid = caster->GetID();
|
||||
strcpy(buffs[slot_id].caster_name, caster->GetName());
|
||||
buffs[slot_id].client = true;
|
||||
} else {
|
||||
buffs[slot_id].casterid = 0;
|
||||
if (caster) {
|
||||
buffs[slot_id].casterid = caster->GetID();
|
||||
strcpy(buffs[slot_id].caster_name, caster->GetName());
|
||||
buffs[slot_id].client = true;
|
||||
} else {
|
||||
buffs[slot_id].casterid = 0;
|
||||
strcpy(buffs[slot_id].caster_name, "");
|
||||
buffs[slot_id].client = false;
|
||||
}
|
||||
}
|
||||
|
||||
buffs[slot_id].ticsremaining = ticsremaining;
|
||||
buffs[slot_id].ticsremaining = ticsremaining;
|
||||
buffs[slot_id].counters = counters;
|
||||
buffs[slot_id].numhits = numhits;
|
||||
buffs[slot_id].melee_rune = melee_rune;
|
||||
buffs[slot_id].magic_rune = magic_rune;
|
||||
buffs[slot_id].persistant_buff = persistent? true: false;
|
||||
buffs[slot_id].persistant_buff = persistent ? true : false;
|
||||
buffs[slot_id].dot_rune = dot_rune;
|
||||
buffs[slot_id].caston_x = caston_x;
|
||||
buffs[slot_id].caston_y = caston_y;
|
||||
buffs[slot_id].caston_z = caston_z;
|
||||
buffs[slot_id].ExtraDIChance = ExtraDIChance;
|
||||
buffs[slot_id].RootBreakChance = 0;
|
||||
buffs[slot_id].UpdateClient = false;
|
||||
|
||||
}
|
||||
buffs[slot_id].caston_y = caston_y;
|
||||
buffs[slot_id].caston_z = caston_z;
|
||||
buffs[slot_id].ExtraDIChance = ExtraDIChance;
|
||||
buffs[slot_id].RootBreakChance = 0;
|
||||
buffs[slot_id].UpdateClient = false;
|
||||
buffs[slot_id].instrument_mod = instrument_mod;
|
||||
}
|
||||
|
||||
max_slots = client->GetMaxBuffSlots();
|
||||
for(int index = 0; index < max_slots; ++index) {
|
||||
if(!IsValidSpell(buffs[index].spellid))
|
||||
for (int index = 0; index < max_slots; ++index) {
|
||||
if (!IsValidSpell(buffs[index].spellid))
|
||||
continue;
|
||||
|
||||
for(int effectIndex = 0; effectIndex < 12; ++effectIndex) {
|
||||
for (int effectIndex = 0; effectIndex < 12; ++effectIndex) {
|
||||
|
||||
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Charm) {
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Illusion) {
|
||||
if(buffs[index].persistant_buff)
|
||||
break;
|
||||
if (spells[buffs[index].spellid].effectid[effectIndex] == SE_Illusion) {
|
||||
if (buffs[index].persistant_buff)
|
||||
break;
|
||||
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
buffs[index].spellid = SPELL_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -3389,7 +3393,7 @@ bool ZoneDatabase::SetCharacterFactionLevel(uint32 char_id, int32 faction_id, in
|
||||
"ON DUPLICATE KEY UPDATE `current_value`=%i,`temp`=%i",
|
||||
char_id, faction_id, value, temp, value, temp);
|
||||
auto results = QueryDatabase(query);
|
||||
|
||||
|
||||
if (!results.Success())
|
||||
return false;
|
||||
else
|
||||
@ -3534,7 +3538,7 @@ uint32 ZoneDatabase::GetCharacterCorpseDecayTimer(uint32 corpse_db_id){
|
||||
auto results = QueryDatabase(query);
|
||||
auto row = results.begin();
|
||||
if (results.Success() && results.RowsAffected() != 0)
|
||||
return atoul(row[0]);
|
||||
return atoul(row[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3621,8 +3625,8 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
|
||||
"`wc_6` = %u, "
|
||||
"`wc_7` = %u, "
|
||||
"`wc_8` = %u, "
|
||||
"`wc_9` = %u ",
|
||||
EscapeString(charname).c_str(),
|
||||
"`wc_9` = %u ",
|
||||
EscapeString(charname).c_str(),
|
||||
zoneid,
|
||||
instanceid,
|
||||
charid,
|
||||
@ -3675,21 +3679,21 @@ uint32 ZoneDatabase::SaveCharacterCorpse(uint32 charid, const char* charname, ui
|
||||
corpse_items_query = StringFormat("REPLACE INTO `character_corpse_items` \n"
|
||||
" (corpse_id, equip_slot, item_id, charges, aug_1, aug_2, aug_3, aug_4, aug_5, aug_6, attuned) \n"
|
||||
" VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
last_insert_id,
|
||||
last_insert_id,
|
||||
dbpc->items[i].equip_slot,
|
||||
dbpc->items[i].item_id,
|
||||
dbpc->items[i].charges,
|
||||
dbpc->items[i].aug_1,
|
||||
dbpc->items[i].aug_2,
|
||||
dbpc->items[i].aug_3,
|
||||
dbpc->items[i].aug_4,
|
||||
dbpc->items[i].item_id,
|
||||
dbpc->items[i].charges,
|
||||
dbpc->items[i].aug_1,
|
||||
dbpc->items[i].aug_2,
|
||||
dbpc->items[i].aug_3,
|
||||
dbpc->items[i].aug_4,
|
||||
dbpc->items[i].aug_5,
|
||||
dbpc->items[i].aug_6,
|
||||
dbpc->items[i].attuned
|
||||
);
|
||||
first_entry = 1;
|
||||
}
|
||||
else{
|
||||
else{
|
||||
corpse_items_query = corpse_items_query + StringFormat(", (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u) \n",
|
||||
last_insert_id,
|
||||
dbpc->items[i].equip_slot,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user