mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-30 23:21:29 +00:00
Merge pull request #172 from KayenEQ/Development
Implemented support for spells_new fields InCombat, OutofCombat
This commit is contained in:
commit
bb9f440882
@ -1,5 +1,17 @@
|
||||
EQEMu Changelog (Started on Sept 24, 2003 15:50)
|
||||
-------------------------------------------------------
|
||||
== 08/02/2014 ==
|
||||
Kayen: Implemented spell_news fields
|
||||
- npc_no_los (check if LOS is required for spells)
|
||||
- InCombat, OutofCombat - Used together to restrict spells to only be cast while
|
||||
in/out of combat (beneficial) or if target is in/out of combat (detrimental).
|
||||
-min_dist, min_dist_mod, max_dist, max_dist_mod - Scales spell power based on targets distance from caster.
|
||||
*This will require further work to fully implement but will work with 90% of live spells as is.
|
||||
*If making custom spells do not include effects that can't be scaled (like a spell trigger)
|
||||
- min_rage sets minimum distance range that must be away from target.
|
||||
|
||||
Required SQL: utils/sql/git/required/2014_08_02_spells_new.sql
|
||||
|
||||
== 07/31/2014 ==
|
||||
Uleat: More inventory slot constant conversions. This should be the bulk of everything..but, due to the size of the server code, there
|
||||
may be some hidden ones. (client_packet.cpp and the client translators still need a thorough review.)
|
||||
|
||||
@ -1710,7 +1710,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
for (y = 0; y < 16; y++)
|
||||
sp[tempid].deities[y]=atoi(row[126+y]);
|
||||
|
||||
sp[tempid].uninterruptable=atoi(row[146]);
|
||||
sp[tempid].uninterruptable=atoi(row[146]) != 0;
|
||||
sp[tempid].ResistDiff=atoi(row[147]);
|
||||
sp[tempid].dot_stacking_exempt=atoi(row[148]);
|
||||
sp[tempid].RecourseLink = atoi(row[150]);
|
||||
@ -1726,6 +1726,7 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
|
||||
sp[tempid].EndurCost=atoi(row[166]);
|
||||
sp[tempid].EndurTimerIndex=atoi(row[167]);
|
||||
sp[tempid].IsDisciplineBuff = atoi(row[168]) != 0;
|
||||
sp[tempid].HateAdded=atoi(row[173]);
|
||||
sp[tempid].EndurUpkeep=atoi(row[174]);
|
||||
sp[tempid].numhitstype = atoi(row[175]);
|
||||
@ -1741,19 +1742,26 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
sp[tempid].viral_targets = atoi(row[191]);
|
||||
sp[tempid].viral_timer = atoi(row[192]);
|
||||
sp[tempid].NimbusEffect = atoi(row[193]);
|
||||
sp[tempid].directional_start = (float)atoi(row[194]);
|
||||
sp[tempid].directional_end = (float)atoi(row[195]);
|
||||
sp[tempid].directional_start = static_cast<float>(atoi(row[194]));
|
||||
sp[tempid].directional_end = static_cast<float>(atoi(row[195]));
|
||||
sp[tempid].not_extendable = atoi(row[197]) != 0;
|
||||
sp[tempid].suspendable = atoi(row[200]) != 0;
|
||||
sp[tempid].viral_range = atoi(row[201]);
|
||||
sp[tempid].spellgroup=atoi(row[207]);
|
||||
sp[tempid].rank = atoi(row[208]);
|
||||
sp[tempid].powerful_flag=atoi(row[209]);
|
||||
sp[tempid].CastRestriction = atoi(row[211]);
|
||||
sp[tempid].AllowRest = atoi(row[212]) != 0;
|
||||
sp[tempid].NotOutofCombat = atoi(row[213]) != 0;
|
||||
sp[tempid].NotInCombat = atoi(row[214]) != 0;
|
||||
sp[tempid].InCombat = atoi(row[213]) != 0;
|
||||
sp[tempid].OutofCombat = atoi(row[214]) != 0;
|
||||
sp[tempid].aemaxtargets = atoi(row[218]);
|
||||
sp[tempid].maxtargets = atoi(row[219]);
|
||||
sp[tempid].persistdeath = atoi(row[224]) != 0;
|
||||
sp[tempid].min_dist = atof(row[227]);
|
||||
sp[tempid].min_dist_mod = atof(row[228]);
|
||||
sp[tempid].max_dist = atof(row[229]);
|
||||
sp[tempid].max_dist_mod = atof(row[230]);
|
||||
sp[tempid].min_range = static_cast<float>(atoi(row[231]));
|
||||
sp[tempid].DamageShieldType = 0;
|
||||
}
|
||||
mysql_free_result(result);
|
||||
|
||||
@ -1040,6 +1040,15 @@ bool IsCastonFadeDurationSpell(uint16 spell_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsPowerDistModSpell(uint16 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;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 GetPartialMeleeRuneReduction(uint32 spell_id)
|
||||
{
|
||||
for (int i = 0; i < EFFECT_COUNT; ++i)
|
||||
|
||||
@ -697,8 +697,8 @@ struct SPDat_Spell_Struct
|
||||
/* 164 */ // for most spells this appears to mimic ResistDiff
|
||||
/* 166 */ int EndurCost;
|
||||
/* 167 */ int8 EndurTimerIndex;
|
||||
/* 168 */ //int IsDisciplineBuff; //Will goto the combat window when cast
|
||||
/* 169 */
|
||||
/* 168 */ bool IsDisciplineBuff; //Will goto the combat window when cast
|
||||
/* 169 - 172*/ //These are zero for ALL spells
|
||||
/* 173 */ int HateAdded;
|
||||
/* 174 */ int EndurUpkeep;
|
||||
/* 175 */ int numhitstype; // defines which type of behavior will tick down the numhit counter.
|
||||
@ -721,23 +721,30 @@ struct SPDat_Spell_Struct
|
||||
/* 197 */ bool not_extendable;
|
||||
/* 198- 199 */
|
||||
/* 200 */ bool suspendable; // buff is suspended in suspended buff zones
|
||||
/* 201 - 202 */
|
||||
/* 201 */ int viral_range;
|
||||
/* 202 */
|
||||
/* 203 */ //int songcap; // individual song cap (how live currently does it, not implemented)
|
||||
/* 204 - 206 */
|
||||
/* 207 */ int spellgroup;
|
||||
/* 208 */ // int rank - increments AA effects with same name
|
||||
/* 208 */ int rank; //increments AA effects with same name
|
||||
/* 209 */ int powerful_flag; // Need more investigation to figure out what to call this, for now we know -1 makes charm spells not break before their duration is complete, it does alot more though
|
||||
/* 210 */ // bool DurationFrozen; ???
|
||||
/* 211 */ int CastRestriction; //Various restriction categories for spells most seem targetable race related but have also seen others for instance only castable if target hp 20% or lower or only if target out of combat
|
||||
/* 212 */ bool AllowRest;
|
||||
/* 213 */ bool NotOutofCombat; //Fail if cast out of combat
|
||||
/* 214 */ bool NotInCombat; //Fail if cast in combat
|
||||
/* 213 */ bool InCombat; //Allow spell if target is in combat
|
||||
/* 214 */ bool OutofCombat; //Allow spell if target is out of combat
|
||||
/* 215 - 217 */
|
||||
/* 219 */ int aemaxtargets; //
|
||||
/* 219 */ int maxtargets; // is used for beam and ring spells for target # limits (not implemented)
|
||||
/* 220 - 223 */
|
||||
/* 218 */ int aemaxtargets; //Is used for various AE effects
|
||||
/* 219 */ int maxtargets; //Is used for beam and ring spells for target # limits (not implemented)
|
||||
/* 220 - 223 */
|
||||
/* 224 */ bool persistdeath; // buff doesn't get stripped on death
|
||||
/* 225 - 236 */ // Not in DB
|
||||
/* 225 - 226 */
|
||||
/* 227 */ float min_dist; //spell power modified by distance from caster (Min Distance)
|
||||
/* 228 */ float min_dist_mod; //spell power modified by distance from caster (Modifier at Min Distance)
|
||||
/* 229 */ float max_dist; //spell power modified by distance from caster (Max Distance)
|
||||
/* 230 */ float max_dist_mod; //spell power modified by distance from caster (Modifier at Max Distance)
|
||||
/* 231 */ float min_range; //Min casting range
|
||||
/* 232 - 236 */
|
||||
uint8 DamageShieldType; // This field does not exist in spells_us.txt
|
||||
};
|
||||
|
||||
@ -838,6 +845,7 @@ bool IsPersistDeathSpell(uint16 spell_id);
|
||||
bool IsSuspendableSpell(uint16 spell_id);
|
||||
uint32 GetMorphTrigger(uint32 spell_id);
|
||||
bool IsCastonFadeDurationSpell(uint16 spell_id);
|
||||
bool IsPowerDistModSpell(uint16 spell_id);
|
||||
uint32 GetPartialMeleeRuneReduction(uint32 spell_id);
|
||||
uint32 GetPartialMagicRuneReduction(uint32 spell_id);
|
||||
uint32 GetPartialMeleeRuneAmount(uint32 spell_id);
|
||||
|
||||
18
utils/sql/git/required/2014_08_02_spells_new.sql
Normal file
18
utils/sql/git/required/2014_08_02_spells_new.sql
Normal file
@ -0,0 +1,18 @@
|
||||
-- spells new talbe update
|
||||
ALTER TABLE `spells_new` CHANGE `NotOutofCombat` `InCombat` INT(11) NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `spells_new` CHANGE `NotInCombat` `OutofCombat` INT(11) NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `spells_new` CHANGE `field201` `viral_range` INT(11) NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `spells_new` CHANGE `field218` `aemaxtargets` INT(11) NOT NULL DEFAULT '0';
|
||||
ALTER TABLE `spells_new` ADD `field225` int( 11 ) NOT NULL DEFAULT '0' AFTER `persistdeath`;
|
||||
ALTER TABLE `spells_new` ADD `field226` int( 11 ) NOT NULL DEFAULT '0' AFTER `field225`;
|
||||
ALTER TABLE `spells_new` ADD `min_dist` float( 0 ) NOT NULL DEFAULT '0' AFTER `field226`;
|
||||
ALTER TABLE `spells_new` ADD `min_dist_mod` float( 0 ) NOT NULL DEFAULT '0' AFTER `min_dist`;
|
||||
ALTER TABLE `spells_new` ADD `max_dist` float( 0 ) NOT NULL DEFAULT '0' AFTER `min_dist_mod`;
|
||||
ALTER TABLE `spells_new` ADD `max_dist_mod` float( 0 ) NOT NULL DEFAULT '0' AFTER `max_dist`;
|
||||
ALTER TABLE `spells_new` ADD `min_range` int( 11 ) NOT NULL DEFAULT '0' AFTER `max_dist_mod`;
|
||||
ALTER TABLE `spells_new` ADD `field232` int( 11 ) NOT NULL DEFAULT '0' AFTER `min_range`;
|
||||
ALTER TABLE `spells_new` ADD `field233` int( 11 ) NOT NULL DEFAULT '0' AFTER `field232`;
|
||||
ALTER TABLE `spells_new` ADD `field234` int( 11 ) NOT NULL DEFAULT '0' AFTER `field233`;
|
||||
ALTER TABLE `spells_new` ADD `field235` int( 11 ) NOT NULL DEFAULT '0' AFTER `field234`;
|
||||
ALTER TABLE `spells_new` ADD `field236` int( 11 ) NOT NULL DEFAULT '0' AFTER `field235`;
|
||||
|
||||
@ -249,6 +249,7 @@
|
||||
#define CORPSEDRAG_BEGIN 4064 //You begin to drag %1.
|
||||
#define CORPSEDRAG_STOPALL 4065 //You stop dragging the corpses.
|
||||
#define CORPSEDRAG_STOP 4066 //You stop dragging the corpse.
|
||||
#define TARGET_TOO_CLOSE 4602 //You are too close to your target. Get farther away.
|
||||
#define WHOALL_NO_RESULTS 5029 //There are no players in EverQuest that match those who filters.
|
||||
#define PETITION_NO_DELETE 5053 //You do not have a petition in the queue.
|
||||
#define PETITION_DELETED 5054 //Your petition was successfully deleted.
|
||||
@ -316,6 +317,10 @@
|
||||
#define PET_NOT_FOCUSING 9263 //No longer focusing on one target, Master.
|
||||
#define PET_NOT_CASTING 9264 //Not casting spells, Master.
|
||||
#define PET_CASTING 9291 //Casting spells normally, Master.
|
||||
#define NO_CAST_IN_COMBAT 9190 //You can not cast this spell while in combat.
|
||||
#define NO_CAST_OUT_OF_COMBAT 9191 //You can not cast this spell while out of combat.
|
||||
#define NO_ABILITY_IN_COMBAT 9192 //You can not use this ability while in combat.
|
||||
#define NO_ABILITY_OUT_OF_COMBAT 9194 //You can not use this ability while out of combat.
|
||||
#define AE_RAMPAGE 11015 //%1 goes on a WILD RAMPAGE!
|
||||
#define FACE_ACCEPTED 12028 //Facial features accepted.
|
||||
#define SPELL_LEVEL_TO_LOW 12048 //You will have to achieve level %1 before you can scribe the %2.
|
||||
|
||||
@ -740,6 +740,8 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
|
||||
float dist = caster->GetAOERange(spell_id);
|
||||
float dist2 = dist * dist;
|
||||
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
|
||||
float dist_targ = 0;
|
||||
|
||||
bool bad = IsDetrimentalSpell(spell_id);
|
||||
bool isnpc = caster->IsNPC();
|
||||
@ -755,7 +757,11 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
continue;
|
||||
if (curmob == caster && !affect_caster) //watch for caster too
|
||||
continue;
|
||||
if (center->DistNoRoot(*curmob) > dist2) //make sure they are in range
|
||||
|
||||
dist_targ = center->DistNoRoot(*curmob);
|
||||
if (dist_targ > dist2) //make sure they are in range
|
||||
continue;
|
||||
if (dist_targ < min_range2) //make sure they are in range
|
||||
continue;
|
||||
if (isnpc && curmob->IsNPC()) { //check npc->npc casting
|
||||
FACTION_VALUE f = curmob->GetReverseFactionCon(caster);
|
||||
@ -786,6 +792,8 @@ void EntityList::AESpell(Mob *caster, Mob *center, uint16 spell_id, bool affect_
|
||||
continue;
|
||||
}
|
||||
|
||||
curmob->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
||||
|
||||
//if we get here... cast the spell.
|
||||
if (IsTargetableAESpell(spell_id) && bad) {
|
||||
if (iCounter < MAX_TARGETS_ALLOWED) {
|
||||
|
||||
@ -4538,7 +4538,7 @@ Mob *EntityList::GetClosestMobByBodyType(Mob *sender, bodyType BodyType)
|
||||
return ClosestMob;
|
||||
}
|
||||
|
||||
void EntityList::GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height, std::list<Mob*> &m_list)
|
||||
void EntityList::GetTargetsForConeArea(Mob *start, float min_radius, float radius, float height, std::list<Mob*> &m_list)
|
||||
{
|
||||
auto it = mob_list.begin();
|
||||
while (it != mob_list.end()) {
|
||||
@ -4547,15 +4547,15 @@ void EntityList::GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height,
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
int32 x_diff = ptr->GetX() - start->GetX();
|
||||
int32 y_diff = ptr->GetY() - start->GetY();
|
||||
int32 z_diff = ptr->GetZ() - start->GetZ();
|
||||
float x_diff = ptr->GetX() - start->GetX();
|
||||
float y_diff = ptr->GetY() - start->GetY();
|
||||
float z_diff = ptr->GetZ() - start->GetZ();
|
||||
|
||||
x_diff *= x_diff;
|
||||
y_diff *= y_diff;
|
||||
z_diff *= z_diff;
|
||||
|
||||
if ((x_diff + y_diff) <= (radius * radius))
|
||||
if ((x_diff + y_diff) <= (radius * radius) && (x_diff + y_diff) >= (min_radius * min_radius))
|
||||
if(z_diff <= (height * height))
|
||||
m_list.push_back(ptr);
|
||||
|
||||
|
||||
@ -406,7 +406,7 @@ public:
|
||||
void GetObjectList(std::list<Object*> &o_list);
|
||||
void GetDoorsList(std::list<Doors*> &d_list);
|
||||
void GetSpawnList(std::list<Spawn2*> &d_list);
|
||||
void GetTargetsForConeArea(Mob *start, uint32 radius, uint32 height, std::list<Mob*> &m_list);
|
||||
void GetTargetsForConeArea(Mob *start, float min_radius, float radius, float height, std::list<Mob*> &m_list);
|
||||
|
||||
void DepopAll(int NPCTypeID, bool StartSpawnTimer = true);
|
||||
|
||||
|
||||
@ -658,6 +658,7 @@ void Group::CastGroupSpell(Mob* caster, uint16 spell_id) {
|
||||
range = caster->GetAOERange(spell_id);
|
||||
|
||||
float range2 = range*range;
|
||||
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
|
||||
|
||||
// caster->SpellOnTarget(spell_id, caster);
|
||||
|
||||
@ -673,7 +674,8 @@ void Group::CastGroupSpell(Mob* caster, uint16 spell_id) {
|
||||
else if(members[z] != nullptr)
|
||||
{
|
||||
distance = caster->DistNoRoot(*members[z]);
|
||||
if(distance <= range2) {
|
||||
if(distance <= range2 && distance >= min_range2) {
|
||||
members[z]->CalcSpellPowerDistanceMod(spell_id, distance);
|
||||
caster->SpellOnTarget(spell_id, members[z]);
|
||||
#ifdef GROUP_BUFF_PETS
|
||||
if(members[z]->GetPet() && members[z]->HasPetAffinity() && !members[z]->GetPet()->IsCharmed())
|
||||
|
||||
@ -567,20 +567,25 @@ void HateList::SpellCast(Mob *caster, uint32 spell_id, float range)
|
||||
//So keep a list of entity ids and look up after
|
||||
std::list<uint32> id_list;
|
||||
range = range * range;
|
||||
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
|
||||
float dist_targ = 0;
|
||||
auto iterator = list.begin();
|
||||
while (iterator != list.end())
|
||||
{
|
||||
tHateEntry *h = (*iterator);
|
||||
if(range > 0)
|
||||
{
|
||||
if(caster->DistNoRoot(*h->ent) <= range)
|
||||
dist_targ = caster->DistNoRoot(*h->ent);
|
||||
if(dist_targ <= range && dist_targ >= min_range2)
|
||||
{
|
||||
id_list.push_back(h->ent->GetID());
|
||||
h->ent->CalcSpellPowerDistanceMod(spell_id, dist_targ);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
id_list.push_back(h->ent->GetID());
|
||||
h->ent->CalcSpellPowerDistanceMod(spell_id, 0, caster);
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
|
||||
@ -182,6 +182,7 @@ Mob::Mob(const char* in_name,
|
||||
has_numhits = false;
|
||||
has_MGB = false;
|
||||
has_ProjectIllusion = false;
|
||||
SpellPowerDistanceMod = 0;
|
||||
|
||||
if(in_aa_title>0)
|
||||
aa_title = in_aa_title;
|
||||
|
||||
@ -615,6 +615,9 @@ public:
|
||||
bool ImprovedTaunt();
|
||||
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
||||
int16 GetSlowMitigation() const {return slow_mitigation;}
|
||||
void CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster = nullptr);
|
||||
inline int16 GetSpellPowerDistanceMod() const { return SpellPowerDistanceMod; };
|
||||
inline void SetSpellPowerDistanceMod(int16 value) { SpellPowerDistanceMod = value; };
|
||||
|
||||
void ModSkillDmgTaken(SkillUseTypes skill_num, int value);
|
||||
int16 GetModSkillDmgTaken(const SkillUseTypes skill_num);
|
||||
@ -1114,6 +1117,7 @@ protected:
|
||||
bool has_numhits;
|
||||
bool has_MGB;
|
||||
bool has_ProjectIllusion;
|
||||
int16 SpellPowerDistanceMod;
|
||||
|
||||
// Bind wound
|
||||
Timer bindwound_timer;
|
||||
|
||||
@ -186,6 +186,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
buffs[buffslot].numhits = numhit;
|
||||
}
|
||||
|
||||
if (!IsPowerDistModSpell(spell_id))
|
||||
SetSpellPowerDistanceMod(0);
|
||||
|
||||
// iterate through the effects in the spell
|
||||
for (i = 0; i < EFFECT_COUNT; i++)
|
||||
{
|
||||
@ -198,6 +201,9 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if(spell_id == SPELL_LAY_ON_HANDS && caster && caster->GetAA(aaImprovedLayOnHands))
|
||||
effect_value = GetMaxHP();
|
||||
|
||||
if (GetSpellPowerDistanceMod())
|
||||
effect_value = effect_value*(GetSpellPowerDistanceMod()/100);
|
||||
|
||||
#ifdef SPELL_EFFECT_SPAM
|
||||
effect_desc[0] = 0;
|
||||
#endif
|
||||
@ -2705,7 +2711,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial)
|
||||
if (buffslot >= 0)
|
||||
break;
|
||||
|
||||
if(IsCasting() && MakeRandomInt(0, 100) <= spells[spell_id].base[i])
|
||||
if(!spells[spell_id].uninterruptable && IsCasting() && MakeRandomInt(0, 100) <= spells[spell_id].base[i])
|
||||
InterruptSpell();
|
||||
|
||||
break;
|
||||
@ -6444,4 +6450,24 @@ bool Mob::CheckSpellCategory(uint16 spell_id, int category_id, int effect_id){
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Mob::CalcSpellPowerDistanceMod(uint16 spell_id, float range, Mob* caster)
|
||||
{
|
||||
if (IsPowerDistModSpell(spell_id)){
|
||||
|
||||
float distance = 0;
|
||||
|
||||
if (caster && !range)
|
||||
distance = caster->CalculateDistance(GetX(), GetY(), GetZ());
|
||||
else
|
||||
distance = sqrt(range);
|
||||
|
||||
float dm_range = spells[spell_id].max_dist - spells[spell_id].min_dist;
|
||||
float dm_mod_interval = spells[spell_id].max_dist_mod - spells[spell_id].min_dist_mod;
|
||||
float dist_from_min = distance - spells[spell_id].min_dist;
|
||||
float mod = spells[spell_id].min_dist_mod + (dist_from_min * (dm_mod_interval/dm_range));
|
||||
mod *= 100.0f;
|
||||
|
||||
SetSpellPowerDistanceMod(static_cast<int>(mod));
|
||||
}
|
||||
}
|
||||
@ -1034,7 +1034,7 @@ void Mob::CastedSpellFinished(uint16 spell_id, uint32 target_id, uint16 slot,
|
||||
|
||||
mlog(SPELLS__CASTING, "Checking Interruption: spell x: %f spell y: %f cur x: %f cur y: %f channelchance %f channeling skill %d\n", GetSpellX(), GetSpellY(), GetX(), GetY(), channelchance, GetSkill(SkillChanneling));
|
||||
|
||||
if(MakeRandomFloat(0, 100) > channelchance) {
|
||||
if(!spells[spell_id].uninterruptable && MakeRandomFloat(0, 100) > channelchance) {
|
||||
mlog(SPELLS__CASTING_ERR, "Casting of %d canceled: interrupted.", spell_id);
|
||||
InterruptSpell();
|
||||
return;
|
||||
@ -1384,6 +1384,52 @@ bool Mob::DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_ce
|
||||
return false;
|
||||
}
|
||||
|
||||
//Must be out of combat. (If Beneficial checks casters combat state, Deterimental checks targets)
|
||||
if (!spells[spell_id].InCombat && spells[spell_id].OutofCombat){
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && spell_target->IsEngaged()) ||
|
||||
(spell_target->IsClient() && spell_target->CastToClient()->GetAggroCount())){
|
||||
Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && IsEngaged()) ||
|
||||
(IsClient() && CastToClient()->GetAggroCount())){
|
||||
if (IsDiscipline(spell_id))
|
||||
Message_StringID(13,NO_ABILITY_IN_COMBAT);
|
||||
else
|
||||
Message_StringID(13,NO_CAST_IN_COMBAT);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Must be in combat. (If Beneficial checks casters combat state, Deterimental checks targets)
|
||||
else if (spells[spell_id].InCombat && !spells[spell_id].OutofCombat){
|
||||
if (IsDetrimentalSpell(spell_id)) {
|
||||
if ( (spell_target->IsNPC() && !spell_target->IsEngaged()) ||
|
||||
(spell_target->IsClient() && !spell_target->CastToClient()->GetAggroCount())){
|
||||
Message_StringID(13,SPELL_NO_EFFECT); //Unsure correct string
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
else if (IsBeneficialSpell(spell_id)) {
|
||||
if ( (IsNPC() && !IsEngaged()) ||
|
||||
(IsClient() && !CastToClient()->GetAggroCount())){
|
||||
if (IsDiscipline(spell_id))
|
||||
Message_StringID(13,NO_ABILITY_OUT_OF_COMBAT);
|
||||
else
|
||||
Message_StringID(13,NO_CAST_OUT_OF_COMBAT);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (targetType)
|
||||
{
|
||||
// single target spells
|
||||
@ -1863,12 +1909,21 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
//casting a spell on somebody but ourself, make sure they are in range
|
||||
float dist2 = DistNoRoot(*spell_target);
|
||||
float range2 = range * range;
|
||||
float min_range2 = spells[spell_id].min_range * spells[spell_id].min_range;
|
||||
if(dist2 > range2) {
|
||||
//target is out of range.
|
||||
mlog(SPELLS__CASTING, "Spell %d: Spell target is out of range (squared: %f > %f)", spell_id, dist2, range2);
|
||||
Message_StringID(13, TARGET_OUT_OF_RANGE);
|
||||
return(false);
|
||||
}
|
||||
else if (dist2 < min_range2){
|
||||
//target is too close range.
|
||||
mlog(SPELLS__CASTING, "Spell %d: Spell target is too close (squared: %f < %f)", spell_id, dist2, min_range2);
|
||||
Message_StringID(13, TARGET_TOO_CLOSE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
spell_target->CalcSpellPowerDistanceMod(spell_id, dist2);
|
||||
}
|
||||
|
||||
//
|
||||
@ -2052,7 +2107,7 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
std::list<Mob*> targets_in_range;
|
||||
std::list<Mob*>::iterator iter;
|
||||
|
||||
entity_list.GetTargetsForConeArea(this, spells[spell_id].aoerange, spells[spell_id].aoerange / 2, targets_in_range);
|
||||
entity_list.GetTargetsForConeArea(this, spells[spell_id].min_range, spells[spell_id].aoerange, spells[spell_id].aoerange / 2, targets_in_range);
|
||||
iter = targets_in_range.begin();
|
||||
while(iter != targets_in_range.end())
|
||||
{
|
||||
@ -2068,16 +2123,20 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16
|
||||
if((heading_to_target >= angle_start && heading_to_target <= 360.0f) ||
|
||||
(heading_to_target >= 0.0f && heading_to_target <= angle_end))
|
||||
{
|
||||
if(CheckLosFN(spell_target))
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, spell_target, false, true, resist_adjust);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(heading_to_target >= angle_start && heading_to_target <= angle_end)
|
||||
{
|
||||
if(CheckLosFN((*iter)))
|
||||
if(CheckLosFN((*iter)) || spells[spell_id].npc_no_los){
|
||||
(*iter)->CalcSpellPowerDistanceMod(spell_id, 0, this);
|
||||
SpellOnTarget(spell_id, (*iter), false, true, resist_adjust);
|
||||
}
|
||||
}
|
||||
}
|
||||
++iter;
|
||||
@ -4625,12 +4684,10 @@ void Mob::Stun(int duration)
|
||||
if(stunned && stunned_timer.GetRemainingTime() > uint32(duration))
|
||||
return;
|
||||
|
||||
if(casting_spell_id) {
|
||||
int persistent_casting = spellbonuses.PersistantCasting + itembonuses.PersistantCasting;
|
||||
if(IsClient())
|
||||
persistent_casting += aabonuses.PersistantCasting;
|
||||
if(IsValidSpell(casting_spell_id) && !spells[casting_spell_id].uninterruptable) {
|
||||
int persistent_casting = spellbonuses.PersistantCasting + itembonuses.PersistantCasting + aabonuses.PersistantCasting;
|
||||
|
||||
if(MakeRandomInt(1,99) > persistent_casting)
|
||||
if(MakeRandomInt(0,99) > persistent_casting)
|
||||
InterruptSpell();
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user