mirror of
https://github.com/EQEmu/Server.git
synced 2026-06-23 16:48:21 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79f250da2d | |||
| 752e6c89f3 | |||
| e962ad3a35 | |||
| 872d494bb6 | |||
| 8a48473dbc | |||
| a208801d1f |
@@ -1462,6 +1462,23 @@ bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect)
|
|||||||
//Allowing anything not confirmed to be restricted / allowed to receive modifiers, as to not inhbit anyone making custom bard songs.
|
//Allowing anything not confirmed to be restricted / allowed to receive modifiers, as to not inhbit anyone making custom bard songs.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsPulsingBardSong(int32 spell_id)
|
||||||
|
{
|
||||||
|
if (!IsValidSpell(spell_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spells[spell_id].buff_duration == 0xFFFF ||
|
||||||
|
spells[spell_id].recast_time> 0 ||
|
||||||
|
spells[spell_id].mana > 0 ||
|
||||||
|
IsEffectInSpell(spell_id, SE_TemporaryPets) ||
|
||||||
|
IsEffectInSpell(spell_id, SE_Familiar)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
|
int GetSpellStatValue(uint32 spell_id, const char* stat_identifier, uint8 slot)
|
||||||
{
|
{
|
||||||
if (!IsValidSpell(spell_id))
|
if (!IsValidSpell(spell_id))
|
||||||
|
|||||||
+7
-3
@@ -179,8 +179,6 @@
|
|||||||
#define SPELLGROUP_FURIOUS_RAMPAGE 38106
|
#define SPELLGROUP_FURIOUS_RAMPAGE 38106
|
||||||
#define SPELLGROUP_SHROUD_OF_PRAYER 41050
|
#define SPELLGROUP_SHROUD_OF_PRAYER 41050
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define EFFECT_COUNT 12
|
#define EFFECT_COUNT 12
|
||||||
#define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2)
|
#define MAX_SPELL_TRIGGER 12 // One for each slot(only 6 for AA since AA use 2)
|
||||||
#define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists.
|
#define MAX_RESISTABLE_EFFECTS 12 // Number of effects that are typcially checked agianst resists.
|
||||||
@@ -193,6 +191,12 @@
|
|||||||
#define MAX_APPEARANCE_EFFECTS 20 //Up to 20 Appearance Effects can be saved to a mobs appearance effect array, these will be sent to other clients when they enter a zone (This is arbitrary)
|
#define MAX_APPEARANCE_EFFECTS 20 //Up to 20 Appearance Effects can be saved to a mobs appearance effect array, these will be sent to other clients when they enter a zone (This is arbitrary)
|
||||||
#define MAX_CAST_ON_SKILL_USE 36 //Actual amount is MAX/3
|
#define MAX_CAST_ON_SKILL_USE 36 //Actual amount is MAX/3
|
||||||
|
|
||||||
|
//instrument item id's used as song components
|
||||||
|
#define INSTRUMENT_HAND_DRUM 13000
|
||||||
|
#define INSTRUMENT_WOODEN_FLUTE 13001
|
||||||
|
#define INSTRUMENT_LUTE 13011
|
||||||
|
#define INSTRUMENT_HORN 13012
|
||||||
|
|
||||||
|
|
||||||
const int Z_AGGRO=10;
|
const int Z_AGGRO=10;
|
||||||
|
|
||||||
@@ -1536,9 +1540,9 @@ int GetViralMinSpreadTime(int32 spell_id);
|
|||||||
int GetViralMaxSpreadTime(int32 spell_id);
|
int GetViralMaxSpreadTime(int32 spell_id);
|
||||||
int GetViralSpreadRange(int32 spell_id);
|
int GetViralSpreadRange(int32 spell_id);
|
||||||
bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect);
|
bool IsInstrumentModAppliedToSpellEffect(int32 spell_id, int effect);
|
||||||
|
bool IsPulsingBardSong(int32 spell_id);
|
||||||
uint32 GetProcLimitTimer(int32 spell_id, int proc_type);
|
uint32 GetProcLimitTimer(int32 spell_id, int proc_type);
|
||||||
bool IgnoreCastingRestriction(int32 spell_id);
|
bool IgnoreCastingRestriction(int32 spell_id);
|
||||||
|
|
||||||
int CalcPetHp(int levelb, int classb, int STA = 75);
|
int CalcPetHp(int levelb, int classb, int STA = 75);
|
||||||
int GetSpellEffectDescNum(uint16 spell_id);
|
int GetSpellEffectDescNum(uint16 spell_id);
|
||||||
DmgShieldType GetDamageShieldType(uint16 spell_id, int32 DSType = 0);
|
DmgShieldType GetDamageShieldType(uint16 spell_id, int32 DSType = 0);
|
||||||
|
|||||||
+47
-30
@@ -1227,65 +1227,65 @@ void Client::IncrementAlternateAdvancementRank(int rank_id) {
|
|||||||
void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
||||||
AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id);
|
AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id);
|
||||||
|
|
||||||
if(!rank) {
|
if (!rank) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AA::Ability *ability = rank->base_ability;
|
AA::Ability *ability = rank->base_ability;
|
||||||
if(!ability) {
|
if (!ability) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!IsValidSpell(rank->spell)) {
|
if (!IsValidSpell(rank->spell)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//do not allow AA to cast if your actively casting another AA.
|
||||||
|
if (rank->spell == casting_spell_id && rank->id == casting_spell_aa_id) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!CanUseAlternateAdvancementRank(rank)) {
|
if (!CanUseAlternateAdvancementRank(rank)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_toggle_passive_hotkey = UseTogglePassiveHotkey(*rank);
|
bool use_toggle_passive_hotkey = UseTogglePassiveHotkey(*rank);
|
||||||
|
|
||||||
//make sure it is not a passive
|
//make sure it is not a passive
|
||||||
if(!rank->effects.empty() && !use_toggle_passive_hotkey) {
|
if (!rank->effects.empty() && !use_toggle_passive_hotkey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 charges = 0;
|
uint32 charges = 0;
|
||||||
// We don't have the AA
|
// We don't have the AA
|
||||||
if (!GetAA(rank_id, &charges))
|
if (!GetAA(rank_id, &charges)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
//if expendable make sure we have charges
|
//if expendable make sure we have charges
|
||||||
if(ability->charges > 0 && charges < 1)
|
if (ability->charges > 0 && charges < 1) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//check cooldown
|
//check cooldown
|
||||||
if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
|
if (!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
|
||||||
uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart);
|
uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart);
|
||||||
uint32 aaremain_hr = aaremain / (60 * 60);
|
uint32 aaremain_hr = aaremain / (60 * 60);
|
||||||
uint32 aaremain_min = (aaremain / 60) % 60;
|
uint32 aaremain_min = (aaremain / 60) % 60;
|
||||||
uint32 aaremain_sec = aaremain % 60;
|
uint32 aaremain_sec = aaremain % 60;
|
||||||
|
|
||||||
if(aaremain_hr >= 1) {
|
if (aaremain_hr >= 1) {
|
||||||
Message(Chat::Red, "You can use this ability again in %u hour(s) %u minute(s) %u seconds",
|
Message(Chat::Red, "You can use this ability again in %u hour(s) %u minute(s) %u seconds",
|
||||||
aaremain_hr, aaremain_min, aaremain_sec);
|
aaremain_hr, aaremain_min, aaremain_sec);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Message(Chat::Red, "You can use this ability again in %u minute(s) %u seconds",
|
Message(Chat::Red, "You can use this ability again in %u minute(s) %u seconds",
|
||||||
aaremain_min, aaremain_sec);
|
aaremain_min, aaremain_sec);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//calculate cooldown
|
if (!IsCastWhileInvis(rank->spell)) {
|
||||||
int cooldown = rank->recast_time - GetAlternateAdvancementCooldownReduction(rank);
|
|
||||||
if(cooldown < 0) {
|
|
||||||
cooldown = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsCastWhileInvis(rank->spell))
|
|
||||||
CommonBreakInvisible();
|
CommonBreakInvisible();
|
||||||
|
}
|
||||||
|
|
||||||
if (spells[rank->spell].sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) {
|
if (spells[rank->spell].sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) {
|
||||||
MessageString(Chat::SpellFailure, SNEAK_RESTRICT);
|
MessageString(Chat::SpellFailure, SNEAK_RESTRICT);
|
||||||
@@ -1293,13 +1293,15 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
// Modern clients don't require pet targeted for AA casts that are ST_Pet
|
// Modern clients don't require pet targeted for AA casts that are ST_Pet
|
||||||
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet)
|
if (spells[rank->spell].target_type == ST_Pet || spells[rank->spell].target_type == ST_SummonedPet) {
|
||||||
target_id = GetPetID();
|
target_id = GetPetID();
|
||||||
|
}
|
||||||
|
|
||||||
// extra handling for cast_not_standing spells
|
// extra handling for cast_not_standing spells
|
||||||
if (!IgnoreCastingRestriction(rank->spell)) {
|
if (!IgnoreCastingRestriction(rank->spell)) {
|
||||||
if (GetAppearance() == eaSitting) // we need to stand!
|
if (GetAppearance() == eaSitting) { // we need to stand!
|
||||||
SetAppearance(eaStanding, false);
|
SetAppearance(eaStanding, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (GetAppearance() != eaStanding) {
|
if (GetAppearance() != eaStanding) {
|
||||||
MessageString(Chat::SpellFailure, STAND_TO_CAST);
|
MessageString(Chat::SpellFailure, STAND_TO_CAST);
|
||||||
@@ -1311,22 +1313,36 @@ void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
|
|||||||
TogglePassiveAlternativeAdvancement(*rank, ability->id);
|
TogglePassiveAlternativeAdvancement(*rank, ability->id);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Bards can cast instant cast AAs while they are casting another song
|
// Bards can cast instant cast AAs while they are casting or channeling item cast.
|
||||||
if (spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
|
if (GetClass() == BARD && IsCasting() && spells[rank->spell].cast_time == 0) {
|
||||||
if (!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false)) {
|
if (!DoCastingChecksOnCaster(rank->spell)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ExpendAlternateAdvancementCharge(ability->id);
|
SpellFinished(rank->spell, entity_list.GetMob(target_id), EQ::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].resist_difficulty, false, -1, false, rank->id);
|
||||||
}
|
}
|
||||||
|
//Known issue: If you attempt to give a Bard an AA with a cast time, the cast timer will not display on the client (no live bard AA have cast time).
|
||||||
else {
|
else {
|
||||||
if (!CastSpell(rank->spell, target_id, EQ::spells::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
|
CastSpell(rank->spell, target_id, EQ::spells::CastingSlot::AltAbility, -1, -1, 0, -1, 0xFFFFFFFF, 0, nullptr, rank->id);
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CastToClient()->GetPTimers().Start(rank->spell_type + pTimerAAStart, cooldown);
|
void Client::SetAARecastTimer(AA::Rank *rank_in, int32 spell_id) {
|
||||||
SendAlternateAdvancementTimer(rank->spell_type, 0, 0);
|
|
||||||
|
if (!rank_in) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate AA cooldown
|
||||||
|
int timer_duration = rank_in->recast_time - GetAlternateAdvancementCooldownReduction(rank_in);
|
||||||
|
|
||||||
|
if (timer_duration <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CastToClient()->GetPTimers().Start(rank_in->spell_type + pTimerAAStart, timer_duration);
|
||||||
|
CastToClient()->SendAlternateAdvancementTimer(rank_in->spell_type, 0, 0);
|
||||||
|
LogSpells("Spell [{}]: Setting AA reuse timer [{}] to [{}]", spell_id, rank_in->spell_type + pTimerAAStart, timer_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
|
int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
|
||||||
@@ -1360,6 +1376,7 @@ int Mob::GetAlternateAdvancementCooldownReduction(AA::Rank *rank_in) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
|
void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
|
||||||
|
|
||||||
for (auto &iter : aa_ranks) {
|
for (auto &iter : aa_ranks) {
|
||||||
AA::Ability *ability = zone->GetAlternateAdvancementAbility(iter.first);
|
AA::Ability *ability = zone->GetAlternateAdvancementAbility(iter.first);
|
||||||
if (ability && aa_id == ability->id) {
|
if (ability && aa_id == ability->id) {
|
||||||
|
|||||||
@@ -660,6 +660,9 @@ bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
|
|||||||
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
if (target->GetSpecialAbility(IMMUNE_DAMAGE_NPC) && IsNPC())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (target->IsHorse())
|
||||||
|
return false;
|
||||||
|
|
||||||
// can't damage own pet (applies to everthing)
|
// can't damage own pet (applies to everthing)
|
||||||
Mob *target_owner = target->GetOwner();
|
Mob *target_owner = target->GetOwner();
|
||||||
Mob *our_owner = GetOwner();
|
Mob *our_owner = GetOwner();
|
||||||
|
|||||||
@@ -436,7 +436,6 @@ Json::Value ApiGetMobListDetail(EQ::Net::WebsocketServerConnection *connection,
|
|||||||
row["cwp"] = mob->GetCWP();
|
row["cwp"] = mob->GetCWP();
|
||||||
row["cwpp"] = mob->GetCWPP();
|
row["cwpp"] = mob->GetCWPP();
|
||||||
row["divine_aura"] = mob->DivineAura();
|
row["divine_aura"] = mob->DivineAura();
|
||||||
row["do_casting_checks"] = mob->DoCastingChecks();
|
|
||||||
row["dont_buff_me_before"] = mob->DontBuffMeBefore();
|
row["dont_buff_me_before"] = mob->DontBuffMeBefore();
|
||||||
row["dont_cure_me_before"] = mob->DontCureMeBefore();
|
row["dont_cure_me_before"] = mob->DontCureMeBefore();
|
||||||
row["dont_dot_me_before"] = mob->DontDotMeBefore();
|
row["dont_dot_me_before"] = mob->DontDotMeBefore();
|
||||||
|
|||||||
+1
-1
@@ -7349,7 +7349,7 @@ void Bot::GenerateSpecialAttacks() {
|
|||||||
|
|
||||||
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) {
|
bool Bot::DoFinishedSpellAETarget(uint16 spell_id, Mob* spellTarget, EQ::spells::CastingSlot slot, bool& stopLogic) {
|
||||||
if(GetClass() == BARD) {
|
if(GetClass() == BARD) {
|
||||||
if(!ApplyNextBardPulse(bardsong, this, bardsong_slot))
|
if(!ApplyBardPulse(bardsong, this, bardsong_slot))
|
||||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||||
|
|
||||||
stopLogic = true;
|
stopLogic = true;
|
||||||
|
|||||||
+6
-1
@@ -1491,7 +1491,12 @@ public:
|
|||||||
void LeaveRaidXTargets(Raid *r);
|
void LeaveRaidXTargets(Raid *r);
|
||||||
bool GroupFollow(Client* inviter);
|
bool GroupFollow(Client* inviter);
|
||||||
inline bool GetRunMode() const { return runmode; }
|
inline bool GetRunMode() const { return runmode; }
|
||||||
void SendItemRecastTimer(uint32 recast_type, uint32 recast_delay = 0);
|
|
||||||
|
void SendItemRecastTimer(int32 recast_type, uint32 recast_delay = 0);
|
||||||
|
void SetItemRecastTimer(int32 spell_id, uint32 inventory_slot);
|
||||||
|
bool HasItemRecastTimer(int32 spell_id, uint32 inventory_slot);
|
||||||
|
void SetDisciplineRecastTimer(int32 spell_id);
|
||||||
|
void SetAARecastTimer(AA::Rank *rank_in, int32 spell_id);
|
||||||
|
|
||||||
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQ::versions::maskRoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
|
inline bool AggroMeterAvailable() const { return ((m_ClientVersionBit & EQ::versions::maskRoF2AndLater)) && RuleB(Character, EnableAggroMeter); } // RoF untested
|
||||||
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
|
inline void SetAggroMeterLock(int in) { m_aggrometer.set_lock_id(in); }
|
||||||
|
|||||||
+41
-16
@@ -4053,7 +4053,6 @@ void Client::Handle_OP_CastSpell(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
EQ::ItemInstance* p_inst = (EQ::ItemInstance*)inst;
|
EQ::ItemInstance* p_inst = (EQ::ItemInstance*)inst;
|
||||||
int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
int i = parse->EventItem(EVENT_ITEM_CLICK_CAST, this, p_inst, nullptr, "", castspell->inventoryslot);
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
CastSpell(item->Click.Effect, castspell->target_id, slot, item->CastTime, 0, 0, castspell->inventoryslot);
|
CastSpell(item->Click.Effect, castspell->target_id, slot, item->CastTime, 0, 0, castspell->inventoryslot);
|
||||||
}
|
}
|
||||||
@@ -8791,6 +8790,7 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
spell_id = item->Click.Effect;
|
spell_id = item->Click.Effect;
|
||||||
|
bool is_casting_bard_song = false;
|
||||||
|
|
||||||
if
|
if
|
||||||
(
|
(
|
||||||
@@ -8812,10 +8812,20 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
SendSpellBarEnable(spell_id);
|
/*
|
||||||
return;
|
Bards on live can click items while casting spell gems, it stops that song cast and replaces it with item click cast.
|
||||||
|
Can not click while casting other items.
|
||||||
|
*/
|
||||||
|
if (GetClass() == BARD && IsCasting() && casting_spell_slot < CastingSlot::MaxGems)
|
||||||
|
{
|
||||||
|
is_casting_bard_song = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SendSpellBarEnable(spell_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modern clients don't require pet targeted for item clicks that are ST_Pet
|
// Modern clients don't require pet targeted for item clicks that are ST_Pet
|
||||||
if (spell_id > 0 && (spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_SummonedPet))
|
if (spell_id > 0 && (spells[spell_id].target_type == ST_Pet || spells[spell_id].target_type == ST_SummonedPet))
|
||||||
target_id = GetPetID();
|
target_id = GetPetID();
|
||||||
@@ -8903,11 +8913,16 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
if (!IsCastWhileInvis(item->Click.Effect))
|
if (!IsCastWhileInvis(item->Click.Effect)) {
|
||||||
CommonBreakInvisible(); // client can't do this for us :(
|
CommonBreakInvisible(); // client can't do this for us :(
|
||||||
CastSpell(item->Click.Effect, target_id, CastingSlot::Item, item->CastTime, 0, 0, slot_id);
|
}
|
||||||
|
if (GetClass() == BARD){
|
||||||
|
DoBardCastingFromItemClick(is_casting_bard_song, item->CastTime, item->Click.Effect, target_id, CastingSlot::Item, slot_id, item->RecastType, item->RecastDelay);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CastSpell(item->Click.Effect, target_id, CastingSlot::Item, item->CastTime, 0, 0, slot_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -8944,9 +8959,15 @@ void Client::Handle_OP_ItemVerifyRequest(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
if (!IsCastWhileInvis(augitem->Click.Effect))
|
if (!IsCastWhileInvis(augitem->Click.Effect)) {
|
||||||
CommonBreakInvisible(); // client can't do this for us :(
|
CommonBreakInvisible(); // client can't do this for us :(
|
||||||
CastSpell(augitem->Click.Effect, target_id, CastingSlot::Item, augitem->CastTime, 0, 0, slot_id);
|
}
|
||||||
|
if (GetClass() == BARD) {
|
||||||
|
DoBardCastingFromItemClick(is_casting_bard_song, augitem->CastTime, augitem->Click.Effect, target_id, CastingSlot::Item, slot_id, augitem->RecastType, augitem->RecastDelay);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CastSpell(augitem->Click.Effect, target_id, CastingSlot::Item, augitem->CastTime, 0, 0, slot_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -9552,16 +9573,20 @@ void Client::Handle_OP_ManaChange(const EQApplicationPacket *app)
|
|||||||
{
|
{
|
||||||
if (app->size == 0) {
|
if (app->size == 0) {
|
||||||
// i think thats the sign to stop the songs
|
// i think thats the sign to stop the songs
|
||||||
if (IsBardSong(casting_spell_id) || bardsong != 0)
|
if (IsBardSong(casting_spell_id) || HasActiveSong()) {
|
||||||
InterruptSpell(SONG_ENDS, 0x121);
|
InterruptSpell(SONG_ENDS, 0x121); //Live doesn't send song end message anymore (~Kayen 1/26/22)
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
InterruptSpell(INTERRUPT_SPELL, 0x121);
|
InterruptSpell(INTERRUPT_SPELL, 0x121);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else // I don't think the client sends proper manachanges
|
/*
|
||||||
{ // with a length, just the 0 len ones for stopping songs
|
I don't think the client sends proper manachanges
|
||||||
//ManaChange_Struct* p = (ManaChange_Struct*)app->pBuffer;
|
with a length, just the 0 len ones for stopping songs
|
||||||
|
ManaChange_Struct* p = (ManaChange_Struct*)app->pBuffer;
|
||||||
|
*/
|
||||||
|
else{
|
||||||
printf("OP_ManaChange from client:\n");
|
printf("OP_ManaChange from client:\n");
|
||||||
DumpPacket(app);
|
DumpPacket(app);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -238,9 +238,9 @@ bool Client::Process() {
|
|||||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!ApplyNextBardPulse(bardsong, song_target, bardsong_slot))
|
if (!ApplyBardPulse(bardsong, song_target, bardsong_slot)) {
|
||||||
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
|
||||||
//SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-124
@@ -800,49 +800,15 @@ bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool instant_recast = true;
|
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
|
||||||
|
if (DoCastingChecksOnCaster(spell_id)) {
|
||||||
if(spell.recast_time > 0) {
|
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline);
|
||||||
uint32 reduced_recast = spell.recast_time / 1000;
|
|
||||||
auto focus = GetFocusEffect(focusReduceRecastTime, spell_id);
|
|
||||||
// do stupid stuff because custom servers.
|
|
||||||
// we really should be able to just do the -= focus but since custom servers could have shorter reuse timers
|
|
||||||
// we have to make sure we don't underflow the uint32 ...
|
|
||||||
// and yes, the focus effect can be used to increase the durations (spell 38944)
|
|
||||||
if (focus > reduced_recast) {
|
|
||||||
reduced_recast = 0;
|
|
||||||
if (GetPTimers().Enabled((uint32)DiscTimer))
|
|
||||||
GetPTimers().Clear(&database, (uint32)DiscTimer);
|
|
||||||
} else {
|
|
||||||
reduced_recast -= focus;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reduced_recast > 0){
|
|
||||||
instant_recast = false;
|
|
||||||
|
|
||||||
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
|
|
||||||
if (DoCastingChecks(spell_id, target)) {
|
|
||||||
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline, 0, -1, spells[spell_id].resist_difficulty, false, -1, (uint32)DiscTimer, reduced_recast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
|
|
||||||
}
|
|
||||||
|
|
||||||
SendDisciplineTimer(spells[spell_id].timer_id, reduced_recast);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
if (instant_recast) {
|
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
|
||||||
if (GetClass() == BARD && IsCasting() && spells[spell_id].cast_time == 0) {
|
|
||||||
if (DoCastingChecks(spell_id, target)) {
|
|
||||||
SpellFinished(spell_id, entity_list.GetMob(target), EQ::spells::CastingSlot::Discipline);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
CastSpell(spell_id, target, EQ::spells::CastingSlot::Discipline);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(true);
|
return(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1194,90 +1160,6 @@ void EntityList::MassGroupBuff(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Causes caster to hit every mob within dist range of center with a bard pulse of spell_id
|
|
||||||
* NPC spells will only affect other NPCs with compatible faction
|
|
||||||
*
|
|
||||||
* @param caster
|
|
||||||
* @param center
|
|
||||||
* @param spell_id
|
|
||||||
* @param affect_caster
|
|
||||||
*/
|
|
||||||
void EntityList::AEBardPulse(
|
|
||||||
Mob *caster,
|
|
||||||
Mob *center,
|
|
||||||
uint16 spell_id,
|
|
||||||
bool affect_caster)
|
|
||||||
{
|
|
||||||
Mob *current_mob = nullptr;
|
|
||||||
float distance = caster->GetAOERange(spell_id);
|
|
||||||
float distance_squared = distance * distance;
|
|
||||||
bool is_detrimental_spell = IsDetrimentalSpell(spell_id);
|
|
||||||
bool is_npc = caster->IsNPC();
|
|
||||||
|
|
||||||
for (auto &it : entity_list.GetCloseMobList(caster, distance)) {
|
|
||||||
current_mob = it.second;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skip self
|
|
||||||
*/
|
|
||||||
if (current_mob == center) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (current_mob == caster && !affect_caster) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DistanceSquared(center->GetPosition(), current_mob->GetPosition()) > distance_squared) { //make sure they are in range
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* check npc->npc casting
|
|
||||||
*/
|
|
||||||
if (is_npc && current_mob->IsNPC()) {
|
|
||||||
FACTION_VALUE faction = current_mob->GetReverseFactionCon(caster);
|
|
||||||
if (is_detrimental_spell) {
|
|
||||||
//affect mobs that are on our hate list, or
|
|
||||||
//which have bad faction with us
|
|
||||||
if (!(caster->CheckAggro(current_mob) || faction == FACTION_THREATENINGLY || faction == FACTION_SCOWLS)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//only affect mobs we would assist.
|
|
||||||
if (!(faction <= FACTION_AMIABLY)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LOS
|
|
||||||
*/
|
|
||||||
if (is_detrimental_spell) {
|
|
||||||
if (!center->CheckLosFN(current_mob)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies...
|
|
||||||
// See notes in AESpell() above for more info.
|
|
||||||
if (caster->IsAttackAllowed(current_mob, true)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (caster->CheckAggro(current_mob)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_mob->BardPulse(spell_id, caster);
|
|
||||||
}
|
|
||||||
if (caster->IsClient()) {
|
|
||||||
caster->CastToClient()->CheckSongSkillIncrease(spell_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rampage - Normal and Duration rampages
|
* Rampage - Normal and Duration rampages
|
||||||
* NPCs handle it differently in Mob::Rampage
|
* NPCs handle it differently in Mob::Rampage
|
||||||
|
|||||||
@@ -422,7 +422,6 @@ public:
|
|||||||
int *max_targets = nullptr
|
int *max_targets = nullptr
|
||||||
);
|
);
|
||||||
void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
void MassGroupBuff(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
||||||
void AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster = true);
|
|
||||||
|
|
||||||
//trap stuff
|
//trap stuff
|
||||||
Mob* GetTrapTrigger(Trap* trap);
|
Mob* GetTrapTrigger(Trap* trap);
|
||||||
|
|||||||
@@ -847,42 +847,6 @@ void Group::CastGroupSpell(Mob* caster, uint16 spell_id) {
|
|||||||
disbandcheck = true;
|
disbandcheck = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// does the caster + group
|
|
||||||
void Group::GroupBardPulse(Mob* caster, uint16 spell_id) {
|
|
||||||
uint32 z;
|
|
||||||
float range, distance;
|
|
||||||
|
|
||||||
if(!caster)
|
|
||||||
return;
|
|
||||||
|
|
||||||
castspell = true;
|
|
||||||
range = caster->GetAOERange(spell_id);
|
|
||||||
|
|
||||||
float range2 = range*range;
|
|
||||||
|
|
||||||
for(z=0; z < MAX_GROUP_MEMBERS; z++) {
|
|
||||||
if(members[z] == caster) {
|
|
||||||
caster->BardPulse(spell_id, caster);
|
|
||||||
#ifdef GROUP_BUFF_PETS
|
|
||||||
if(caster->GetPet() && caster->HasPetAffinity() && !caster->GetPet()->IsCharmed())
|
|
||||||
caster->BardPulse(spell_id, caster->GetPet());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if(members[z] != nullptr)
|
|
||||||
{
|
|
||||||
distance = DistanceSquared(caster->GetPosition(), members[z]->GetPosition());
|
|
||||||
if(distance <= range2) {
|
|
||||||
members[z]->BardPulse(spell_id, caster);
|
|
||||||
#ifdef GROUP_BUFF_PETS
|
|
||||||
if(members[z]->GetPet() && members[z]->HasPetAffinity() && !members[z]->GetPet()->IsCharmed())
|
|
||||||
members[z]->GetPet()->BardPulse(spell_id, caster);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
LogSpells("Group bard pulse: [{}] is out of range [{}] at distance [{}] from [{}]", members[z]->GetName(), range, distance, caster->GetName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Group::IsGroupMember(Mob* client)
|
bool Group::IsGroupMember(Mob* client)
|
||||||
{
|
{
|
||||||
bool Result = false;
|
bool Result = false;
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ public:
|
|||||||
bool IsGroup() { return true; }
|
bool IsGroup() { return true; }
|
||||||
void SendGroupJoinOOZ(Mob* NewMember);
|
void SendGroupJoinOOZ(Mob* NewMember);
|
||||||
void CastGroupSpell(Mob* caster,uint16 spellid);
|
void CastGroupSpell(Mob* caster,uint16 spellid);
|
||||||
void GroupBardPulse(Mob* caster,uint16 spellid);
|
|
||||||
void SplitExp(uint32 exp, Mob* other);
|
void SplitExp(uint32 exp, Mob* other);
|
||||||
void GroupMessage(Mob* sender,uint8 language,uint8 lang_skill,const char* message);
|
void GroupMessage(Mob* sender,uint8 language,uint8 lang_skill,const char* message);
|
||||||
void GroupMessageString(Mob* sender, uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0);
|
void GroupMessageString(Mob* sender, uint32 type, uint32 string_id, const char* message,const char* message2=0,const char* message3=0,const char* message4=0,const char* message5=0,const char* message6=0,const char* message7=0,const char* message8=0,const char* message9=0, uint32 distance = 0);
|
||||||
|
|||||||
+19
-6
@@ -3984,6 +3984,16 @@ void Mob::ExecWeaponProc(const EQ::ItemInstance *inst, uint16 spell_id, Mob *on,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsSilenced() && !IsDiscipline(spell_id)) {
|
||||||
|
MessageString(Chat::Red, SILENCED_STRING);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsAmnesiad() && IsDiscipline(spell_id)) {
|
||||||
|
MessageString(Chat::Red, MELEE_SILENCE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(inst && IsClient()) {
|
if(inst && IsClient()) {
|
||||||
//const cast is dirty but it would require redoing a ton of interfaces at this point
|
//const cast is dirty but it would require redoing a ton of interfaces at this point
|
||||||
//It should be safe as we don't have any truly const EQ::ItemInstance floating around anywhere.
|
//It should be safe as we don't have any truly const EQ::ItemInstance floating around anywhere.
|
||||||
@@ -4465,14 +4475,15 @@ void Mob::TryTwincast(Mob *caster, Mob *target, uint32 spell_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Used for effects that should occur after the completion of the spell
|
//Used for effects that should occur after the completion of the spell
|
||||||
void Mob::TryOnSpellFinished(Mob *caster, Mob *target, uint16 spell_id)
|
void Mob::ApplyHealthTransferDamage(Mob *caster, Mob *target, uint16 spell_id)
|
||||||
{
|
{
|
||||||
if (!IsValidSpell(spell_id))
|
if (!IsValidSpell(spell_id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*Apply damage from Lifeburn type effects on caster at end of spell cast.
|
/*
|
||||||
This allows for the AE spells to function without repeatedly killing caster
|
Apply damage from Lifeburn type effects on caster at end of spell cast.
|
||||||
Damage or heal portion can be found as regular single use spell effect
|
This allows for the AE spells to function without repeatedly killing caster
|
||||||
|
Damage or heal portion can be found as regular single use spell effect
|
||||||
*/
|
*/
|
||||||
if (IsEffectInSpell(spell_id, SE_Health_Transfer)){
|
if (IsEffectInSpell(spell_id, SE_Health_Transfer)){
|
||||||
for (int i = 0; i < EFFECT_COUNT; i++) {
|
for (int i = 0; i < EFFECT_COUNT; i++) {
|
||||||
@@ -4481,10 +4492,12 @@ void Mob::TryOnSpellFinished(Mob *caster, Mob *target, uint16 spell_id)
|
|||||||
int new_hp = GetMaxHP();
|
int new_hp = GetMaxHP();
|
||||||
new_hp -= GetMaxHP() * spells[spell_id].base_value[i] / 1000;
|
new_hp -= GetMaxHP() * spells[spell_id].base_value[i] / 1000;
|
||||||
|
|
||||||
if (new_hp > 0)
|
if (new_hp > 0) {
|
||||||
SetHP(new_hp);
|
SetHP(new_hp);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
Kill();
|
Kill();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-10
@@ -285,11 +285,6 @@ public:
|
|||||||
void SetInvisible(uint8 state);
|
void SetInvisible(uint8 state);
|
||||||
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
|
void SetMobTextureProfile(uint8 material_slot, uint16 texture, uint32 color = 0, uint32 hero_forge_model = 0);
|
||||||
|
|
||||||
//Song
|
|
||||||
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
|
||||||
bool ApplyNextBardPulse(uint16 spell_id, Mob *spell_target, EQ::spells::CastingSlot slot);
|
|
||||||
void BardPulse(uint16 spell_id, Mob *caster);
|
|
||||||
|
|
||||||
//Spell
|
//Spell
|
||||||
void SendSpellEffect(uint32 effect_id, uint32 duration, uint32 finish_delay, bool zone_wide,
|
void SendSpellEffect(uint32 effect_id, uint32 duration, uint32 finish_delay, bool zone_wide,
|
||||||
uint32 unk020, bool perm_effect = false, Client *c = nullptr, uint32 caster_id = 0, uint32 target_id = 0);
|
uint32 unk020, bool perm_effect = false, Client *c = nullptr, uint32 caster_id = 0, uint32 target_id = 0);
|
||||||
@@ -331,13 +326,16 @@ public:
|
|||||||
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQ::spells::CastingSlot slot, uint16 mana_used,
|
void CastedSpellFinished(uint16 spell_id, uint32 target_id, EQ::spells::CastingSlot slot, uint16 mana_used,
|
||||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0);
|
||||||
bool SpellFinished(uint16 spell_id, Mob *target, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, uint16 mana_used = 0,
|
bool SpellFinished(uint16 spell_id, Mob *target, EQ::spells::CastingSlot slot = EQ::spells::CastingSlot::Item, uint16 mana_used = 0,
|
||||||
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, uint32 timer = 0xFFFFFFFF, uint32 timer_duration = 0);
|
uint32 inventory_slot = 0xFFFFFFFF, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, bool from_casted_spell = false, uint32 aa_id = 0);
|
||||||
void SendBeginCast(uint16 spell_id, uint32 casttime);
|
void SendBeginCast(uint16 spell_id, uint32 casttime);
|
||||||
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, int reflect_effectiveness = 0,
|
virtual bool SpellOnTarget(uint16 spell_id, Mob* spelltar, int reflect_effectiveness = 0,
|
||||||
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, int32 duration_override = 0);
|
bool use_resist_adjust = false, int16 resist_adjust = 0, bool isproc = false, int level_override = -1, int32 duration_override = 0);
|
||||||
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1, int reflect_effectiveness = 0, int32 duration_override = 0);
|
virtual bool SpellEffect(Mob* caster, uint16 spell_id, float partial = 100, int level_override = -1, int reflect_effectiveness = 0, int32 duration_override = 0);
|
||||||
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
|
virtual bool DetermineSpellTargets(uint16 spell_id, Mob *&spell_target, Mob *&ae_center,
|
||||||
CastAction_type &CastAction, EQ::spells::CastingSlot slot, bool isproc = false);
|
CastAction_type &CastAction, EQ::spells::CastingSlot slot, bool isproc = false);
|
||||||
|
bool DoCastingChecksOnCaster(int32 spell_id);
|
||||||
|
bool DoCastingChecksZoneRestrictions(bool check_on_casting, int32 spell_id);
|
||||||
|
bool DoCastingChecksOnTarget(bool check_on_casting, int32 spell_id, Mob* spell_target);
|
||||||
virtual bool CheckFizzle(uint16 spell_id);
|
virtual bool CheckFizzle(uint16 spell_id);
|
||||||
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
virtual bool CheckSpellLevelRestriction(uint16 spell_id);
|
||||||
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
virtual bool IsImmuneToSpell(uint16 spell_id, Mob *caster);
|
||||||
@@ -345,9 +343,9 @@ public:
|
|||||||
void InterruptSpell(uint16 spellid = SPELL_UNKNOWN);
|
void InterruptSpell(uint16 spellid = SPELL_UNKNOWN);
|
||||||
void InterruptSpell(uint16, uint16, uint16 spellid = SPELL_UNKNOWN);
|
void InterruptSpell(uint16, uint16, uint16 spellid = SPELL_UNKNOWN);
|
||||||
void StopCasting();
|
void StopCasting();
|
||||||
|
void StopCastSpell(int32 spell_id, bool send_spellbar_enable);
|
||||||
inline bool IsCasting() const { return((casting_spell_id != 0)); }
|
inline bool IsCasting() const { return((casting_spell_id != 0)); }
|
||||||
uint16 CastingSpellID() const { return casting_spell_id; }
|
uint16 CastingSpellID() const { return casting_spell_id; }
|
||||||
bool DoCastingChecks(int32 spell_id = SPELL_UNKNOWN, uint16 target_id = 0);
|
|
||||||
bool TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier);
|
bool TryDispel(uint8 caster_level, uint8 buff_level, int level_modifier);
|
||||||
bool TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed = 1.5f);
|
bool TrySpellProjectile(Mob* spell_target, uint16 spell_id, float speed = 1.5f);
|
||||||
void ResourceTap(int32 damage, uint16 spell_id);
|
void ResourceTap(int32 damage, uint16 spell_id);
|
||||||
@@ -355,11 +353,20 @@ public:
|
|||||||
void CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ);
|
void CalcDestFromHeading(float heading, float distance, float MaxZDiff, float StartX, float StartY, float &dX, float &dY, float &dZ);
|
||||||
void BeamDirectional(uint16 spell_id, int16 resist_adjust);
|
void BeamDirectional(uint16 spell_id, int16 resist_adjust);
|
||||||
void ConeDirectional(uint16 spell_id, int16 resist_adjust);
|
void ConeDirectional(uint16 spell_id, int16 resist_adjust);
|
||||||
void TryOnSpellFinished(Mob *caster, Mob *target, uint16 spell_id);
|
void ApplyHealthTransferDamage(Mob *caster, Mob *target, uint16 spell_id);
|
||||||
void ApplySpellEffectIllusion(int32 spell_id, Mob* caster, int buffslot, int base, int limit, int max);
|
void ApplySpellEffectIllusion(int32 spell_id, Mob* caster, int buffslot, int base, int limit, int max);
|
||||||
void ApplyIllusionToCorpse(int32 spell_id, Corpse* new_corpse);
|
void ApplyIllusionToCorpse(int32 spell_id, Corpse* new_corpse);
|
||||||
void SendIllusionWearChange(Client* c);
|
void SendIllusionWearChange(Client* c);
|
||||||
|
|
||||||
|
//Bard
|
||||||
|
bool ApplyBardPulse(int32 spell_id, Mob *spell_target, EQ::spells::CastingSlot slot);
|
||||||
|
bool IsActiveBardSong(int32 spell_id);
|
||||||
|
bool HasActiveSong() const { return(bardsong != 0); }
|
||||||
|
void ZeroBardPulseVars();
|
||||||
|
void DoBardCastingFromItemClick(bool is_casting_bard_song, uint32 cast_time, int32 spell_id, uint16 target_id, EQ::spells::CastingSlot slot, uint32 item_slot,
|
||||||
|
uint32 recast_type , uint32 recast_delay);
|
||||||
|
bool UseBardSpellLogic(uint16 spell_id = 0xffff, int slot = -1);
|
||||||
|
|
||||||
//Buff
|
//Buff
|
||||||
void BuffProcess();
|
void BuffProcess();
|
||||||
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
virtual void DoBuffTic(const Buffs_Struct &buff, int slot, Mob* caster = nullptr);
|
||||||
@@ -847,6 +854,7 @@ public:
|
|||||||
int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg);
|
int32 GetExtraSpellAmt(uint16 spell_id, int32 extra_spell_amt, int32 base_spell_dmg);
|
||||||
void MeleeLifeTap(int32 damage);
|
void MeleeLifeTap(int32 damage);
|
||||||
bool PassCastRestriction(int value);
|
bool PassCastRestriction(int value);
|
||||||
|
void SendCastRestrictionMessage(int requirement_id, bool is_target_requirement = true, bool is_discipline = false);
|
||||||
bool ImprovedTaunt();
|
bool ImprovedTaunt();
|
||||||
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
bool TryRootFadeByDamage(int buffslot, Mob* attacker);
|
||||||
float GetSlowMitigation() const { return slow_mitigation; }
|
float GetSlowMitigation() const { return slow_mitigation; }
|
||||||
@@ -1126,7 +1134,6 @@ public:
|
|||||||
|
|
||||||
void InstillDoubt(Mob *who);
|
void InstillDoubt(Mob *who);
|
||||||
int16 GetResist(uint8 type) const;
|
int16 GetResist(uint8 type) const;
|
||||||
bool HasActiveSong() const { return(bardsong != 0); }
|
|
||||||
bool Charmed() const { return typeofpet == petCharmed; }
|
bool Charmed() const { return typeofpet == petCharmed; }
|
||||||
static uint32 GetLevelHP(uint8 tlevel);
|
static uint32 GetLevelHP(uint8 tlevel);
|
||||||
uint32 GetZoneID() const; //for perl
|
uint32 GetZoneID() const; //for perl
|
||||||
@@ -1735,7 +1742,6 @@ protected:
|
|||||||
MobMovementManager *mMovementManager;
|
MobMovementManager *mMovementManager;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _StopSong(); //this is not what you think it is
|
|
||||||
Mob* target;
|
Mob* target;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+24
-2
@@ -2761,9 +2761,8 @@ void NPC::ApplyAISpellEffects(StatBonuses* newbon)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// adds a spell to the list, taking into account priority and resorting list as needed.
|
// adds a spell to the list, taking into account priority and resorting list as needed.
|
||||||
void NPC::AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value)
|
void NPC::AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value, bool apply_bonus)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(!iSpellEffectID)
|
if(!iSpellEffectID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -2775,6 +2774,29 @@ void NPC::AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base_value, int32
|
|||||||
t.limit = limit;
|
t.limit = limit;
|
||||||
t.max_value = max_value;
|
t.max_value = max_value;
|
||||||
AIspellsEffects.push_back(t);
|
AIspellsEffects.push_back(t);
|
||||||
|
|
||||||
|
//we recalculate if applied from quest script.
|
||||||
|
if (apply_bonus) {
|
||||||
|
CalcBonuses();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NPC::RemoveSpellEffectFromNPCList(uint16 iSpellEffectID, bool apply_bonus)
|
||||||
|
{
|
||||||
|
auto iter = AIspellsEffects.begin();
|
||||||
|
while (iter != AIspellsEffects.end())
|
||||||
|
{
|
||||||
|
if ((*iter).spelleffectid == iSpellEffectID)
|
||||||
|
{
|
||||||
|
iter = AIspellsEffects.erase(iter);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apply_bonus) {
|
||||||
|
CalcBonuses();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsSpellEffectInList(DBnpcspellseffects_Struct* spelleffect_list, uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value) {
|
bool IsSpellEffectInList(DBnpcspellseffects_Struct* spelleffect_list, uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value) {
|
||||||
|
|||||||
+2
-1
@@ -449,8 +449,9 @@ public:
|
|||||||
|
|
||||||
uint32 GetAdventureTemplate() const { return adventure_template_id; }
|
uint32 GetAdventureTemplate() const { return adventure_template_id; }
|
||||||
void AddSpellToNPCList(int16 iPriority, uint16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp);
|
void AddSpellToNPCList(int16 iPriority, uint16 iSpellID, uint32 iType, int16 iManaCost, int32 iRecastDelay, int16 iResistAdjust, int8 min_hp, int8 max_hp);
|
||||||
void AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value);
|
void AddSpellEffectToNPCList(uint16 iSpellEffectID, int32 base_value, int32 limit, int32 max_value, bool apply_bonus = false);
|
||||||
void RemoveSpellFromNPCList(uint16 spell_id);
|
void RemoveSpellFromNPCList(uint16 spell_id);
|
||||||
|
void RemoveSpellEffectFromNPCList(uint16 iSpellEffectID, bool apply_bonus = false);
|
||||||
Timer *GetRefaceTimer() const { return reface_timer; }
|
Timer *GetRefaceTimer() const { return reface_timer; }
|
||||||
const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; }
|
const uint32 GetAltCurrencyType() const { return NPCTypedata->alt_currency_type; }
|
||||||
|
|
||||||
|
|||||||
@@ -1845,6 +1845,40 @@ XS(XS_NPC_GetLootList) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_AddAISpellEffect); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_NPC_AddAISpellEffect) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 5)
|
||||||
|
Perl_croak(aTHX_ "Usage: NPC::AddAISpellEffect(THIS, spell_effect id, base_value, limit_value, max_value)"); // @categories Spells and Disciplines
|
||||||
|
{
|
||||||
|
NPC *THIS;
|
||||||
|
|
||||||
|
int spell_effect_id = (int)SvIV(ST(1));
|
||||||
|
int base_value = (int)SvIV(ST(2));
|
||||||
|
int limit_value = (int)SvIV(ST(3));
|
||||||
|
int max_value = (int)SvIV(ST(4));
|
||||||
|
|
||||||
|
VALIDATE_THIS_IS_NPC;
|
||||||
|
THIS->AddSpellEffectToNPCList(spell_effect_id, base_value, limit_value, max_value, true);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
XS(XS_NPC_RemoveAISpellEffect); /* prototype to pass -Wmissing-prototypes */
|
||||||
|
XS(XS_NPC_RemoveAISpellEffect) {
|
||||||
|
dXSARGS;
|
||||||
|
if (items != 2)
|
||||||
|
Perl_croak(aTHX_ "Usage: NPC::RemoveAISpellEffect(THIS, int spelleffect_id)"); // @categories Spells and Disciplines
|
||||||
|
{
|
||||||
|
NPC *THIS;
|
||||||
|
int spell_effect_id = (int)SvIV(ST(1));
|
||||||
|
VALIDATE_THIS_IS_NPC;
|
||||||
|
THIS->RemoveSpellEffectFromNPCList(spell_effect_id, true);
|
||||||
|
}
|
||||||
|
XSRETURN_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
#endif
|
#endif
|
||||||
@@ -1864,6 +1898,7 @@ XS(boot_NPC) {
|
|||||||
XS_VERSION_BOOTCHECK;
|
XS_VERSION_BOOTCHECK;
|
||||||
newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$$");
|
newXSproto(strcpy(buf, "AI_SetRoambox"), XS_NPC_AI_SetRoambox, file, "$$$$$$;$$");
|
||||||
newXSproto(strcpy(buf, "AddAISpell"), XS_NPC_AddSpellToNPCList, file, "$$$$$$$");
|
newXSproto(strcpy(buf, "AddAISpell"), XS_NPC_AddSpellToNPCList, file, "$$$$$$$");
|
||||||
|
newXSproto(strcpy(buf, "AddAISpellEffect"), XS_NPC_AddAISpellEffect, file, "$$$$$");
|
||||||
newXSproto(strcpy(buf, "AddCash"), XS_NPC_AddCash, file, "$$$$$");
|
newXSproto(strcpy(buf, "AddCash"), XS_NPC_AddCash, file, "$$$$$");
|
||||||
newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$");
|
newXSproto(strcpy(buf, "AddDefensiveProc"), XS_NPC_AddDefensiveProc, file, "$$$");
|
||||||
newXSproto(strcpy(buf, "AddItem"), XS_NPC_AddItem, file, "$$;$$$$$$$$");
|
newXSproto(strcpy(buf, "AddItem"), XS_NPC_AddItem, file, "$$;$$$$$$$$");
|
||||||
@@ -1939,6 +1974,7 @@ XS(boot_NPC) {
|
|||||||
newXSproto(strcpy(buf, "PickPocket"), XS_NPC_PickPocket, file, "$$");
|
newXSproto(strcpy(buf, "PickPocket"), XS_NPC_PickPocket, file, "$$");
|
||||||
newXSproto(strcpy(buf, "RecalculateSkills"), XS_NPC_RecalculateSkills, file, "$");
|
newXSproto(strcpy(buf, "RecalculateSkills"), XS_NPC_RecalculateSkills, file, "$");
|
||||||
newXSproto(strcpy(buf, "RemoveAISpell"), XS_NPC_RemoveSpellFromNPCList, file, "$$");
|
newXSproto(strcpy(buf, "RemoveAISpell"), XS_NPC_RemoveSpellFromNPCList, file, "$$");
|
||||||
|
newXSproto(strcpy(buf, "RemoveAISpellEffect"), XS_NPC_RemoveAISpellEffect, file, "$$");
|
||||||
newXSproto(strcpy(buf, "RemoveCash"), XS_NPC_RemoveCash, file, "$");
|
newXSproto(strcpy(buf, "RemoveCash"), XS_NPC_RemoveCash, file, "$");
|
||||||
newXSproto(strcpy(buf, "RemoveDefensiveProc"), XS_NPC_RemoveDefensiveProc, file, "$$");
|
newXSproto(strcpy(buf, "RemoveDefensiveProc"), XS_NPC_RemoveDefensiveProc, file, "$$");
|
||||||
newXSproto(strcpy(buf, "RemoveFromHateList"), XS_NPC_RemoveFromHateList, file, "$$");
|
newXSproto(strcpy(buf, "RemoveFromHateList"), XS_NPC_RemoveFromHateList, file, "$$");
|
||||||
|
|||||||
@@ -827,42 +827,6 @@ void Raid::SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Raid::GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid){
|
|
||||||
uint32 z;
|
|
||||||
float range, distance;
|
|
||||||
|
|
||||||
if(!caster)
|
|
||||||
return;
|
|
||||||
|
|
||||||
range = caster->GetAOERange(spellid);
|
|
||||||
|
|
||||||
float range2 = range*range;
|
|
||||||
|
|
||||||
for(z=0; z < MAX_RAID_MEMBERS; z++) {
|
|
||||||
if(members[z].member == caster) {
|
|
||||||
caster->BardPulse(spellid, caster);
|
|
||||||
#ifdef GROUP_BUFF_PETS
|
|
||||||
if(caster->GetPet() && caster->HasPetAffinity() && !caster->GetPet()->IsCharmed())
|
|
||||||
caster->BardPulse(spellid, caster->GetPet());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if(members[z].member != nullptr)
|
|
||||||
{
|
|
||||||
if(members[z].GroupNumber == gid){
|
|
||||||
distance = DistanceSquared(caster->GetPosition(), members[z].member->GetPosition());
|
|
||||||
if(distance <= range2) {
|
|
||||||
members[z].member->BardPulse(spellid, caster);
|
|
||||||
#ifdef GROUP_BUFF_PETS
|
|
||||||
if(members[z].member->GetPet() && members[z].member->HasPetAffinity() && !members[z].member->GetPet()->IsCharmed())
|
|
||||||
members[z].member->GetPet()->BardPulse(spellid, caster);
|
|
||||||
#endif
|
|
||||||
} else
|
|
||||||
LogSpells("Group bard pulse: [{}] is out of range [{}] at distance [{}] from [{}]", members[z].member->GetName(), range, distance, caster->GetName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Raid::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid)
|
void Raid::TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < MAX_RAID_MEMBERS; i++)
|
for(int i = 0; i < MAX_RAID_MEMBERS; i++)
|
||||||
|
|||||||
@@ -160,7 +160,6 @@ public:
|
|||||||
void BalanceMana(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0);
|
void BalanceMana(int32 penalty, uint32 gid, float range = 0, Mob* caster = nullptr, int32 limit = 0);
|
||||||
void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 0);
|
void HealGroup(uint32 heal_amt, Mob* caster, uint32 gid, float range = 0);
|
||||||
void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
void SplitMoney(uint32 gid, uint32 copper, uint32 silver, uint32 gold, uint32 platinum, Client *splitter = nullptr);
|
||||||
void GroupBardPulse(Mob* caster, uint16 spellid, uint32 gid);
|
|
||||||
|
|
||||||
void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid);
|
void TeleportGroup(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading, uint32 gid);
|
||||||
void TeleportRaid(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading);
|
void TeleportRaid(Mob* sender, uint32 zoneID, uint16 instance_id, float x, float y, float z, float heading);
|
||||||
|
|||||||
+1114
-9
File diff suppressed because it is too large
Load Diff
+772
-693
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user