mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-14 07:42:29 +00:00
[Spells] Implemented SPA 281 SE_PetFeignMinion (#1900)
* start * update * debugs in * test * clean up * debugs removed * Update mob_ai.cpp * Update spdat.h * [Spells] Implemented SPA 281 SE_PetFeignMinion debug remoevd * [Spells] Implemented SPA 281 SE_PetFeignMinion npc forget timer * [Spells] Implemented SPA 281 SE_PetFeignMinion
This commit is contained in:
parent
7f23c93ce5
commit
323b35989c
@ -26,6 +26,7 @@
|
|||||||
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
|
#define SPELLBOOK_UNKNOWN 0xFFFFFFFF //player profile spells are 32 bit
|
||||||
|
|
||||||
//some spell IDs which will prolly change, but are needed
|
//some spell IDs which will prolly change, but are needed
|
||||||
|
#define SPELL_LIFEBURN 2755
|
||||||
#define SPELL_LEECH_TOUCH 2766
|
#define SPELL_LEECH_TOUCH 2766
|
||||||
#define SPELL_LAY_ON_HANDS 87
|
#define SPELL_LAY_ON_HANDS 87
|
||||||
#define SPELL_HARM_TOUCH 88
|
#define SPELL_HARM_TOUCH 88
|
||||||
@ -998,7 +999,7 @@ typedef enum {
|
|||||||
#define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage)
|
#define SE_FinishingBlow 278 // implemented[AA] - chance to do massive damage under 10% HP (base1 = chance, base2 = damage)
|
||||||
#define SE_Flurry 279 // implemented
|
#define SE_Flurry 279 // implemented
|
||||||
#define SE_PetFlurry 280 // implemented[AA]
|
#define SE_PetFlurry 280 // implemented[AA]
|
||||||
#define SE_FeignedMinion 281 // *not implemented[AA] ability allows you to instruct your pet to feign death via the '/pet feign' command. value = succeed chance
|
#define SE_FeignedMinion 281 // implemented, ability allows you to instruct your pet to feign death via the '/pet feign' command, base: succeed chance, limit: none, max: none, Note: Only implemented as an AA.
|
||||||
#define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent.
|
#define SE_ImprovedBindWound 282 // implemented[AA] - increase bind wound amount by percent.
|
||||||
#define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk
|
#define SE_DoubleSpecialAttack 283 // implemented[AA] - Chance to perform second special attack as monk
|
||||||
//#define SE_LoHSetHeal 284 // not used
|
//#define SE_LoHSetHeal 284 // not used
|
||||||
|
|||||||
@ -1402,45 +1402,62 @@ int32 Mob::CheckHealAggroAmount(uint16 spell_id, Mob *target, uint32 heal_possib
|
|||||||
return std::max(0, AggroAmount);
|
return std::max(0, AggroAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::AddFeignMemory(Client* attacker) {
|
void Mob::AddFeignMemory(Mob* attacker) {
|
||||||
if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr)
|
if (feign_memory_list.empty() && AI_feign_remember_timer != nullptr) {
|
||||||
AI_feign_remember_timer->Start(AIfeignremember_delay);
|
AI_feign_remember_timer->Start(AIfeignremember_delay);
|
||||||
feign_memory_list.insert(attacker->CharacterID());
|
}
|
||||||
|
|
||||||
|
if (attacker) {
|
||||||
|
feign_memory_list.insert(attacker->GetID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::RemoveFromFeignMemory(Client* attacker) {
|
void Mob::RemoveFromFeignMemory(Mob* attacker) {
|
||||||
feign_memory_list.erase(attacker->CharacterID());
|
|
||||||
if(feign_memory_list.empty() && AI_feign_remember_timer != nullptr)
|
if (!attacker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
feign_memory_list.erase(attacker->GetID());
|
||||||
|
if (feign_memory_list.empty() && AI_feign_remember_timer != nullptr) {
|
||||||
AI_feign_remember_timer->Disable();
|
AI_feign_remember_timer->Disable();
|
||||||
|
}
|
||||||
if(feign_memory_list.empty())
|
if(feign_memory_list.empty())
|
||||||
{
|
{
|
||||||
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
|
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
|
||||||
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
|
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
|
||||||
if(AI_feign_remember_timer != nullptr)
|
if (AI_feign_remember_timer != nullptr) {
|
||||||
AI_feign_remember_timer->Disable();
|
AI_feign_remember_timer->Disable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mob::ClearFeignMemory() {
|
void Mob::ClearFeignMemory() {
|
||||||
auto RememberedCharID = feign_memory_list.begin();
|
auto remembered_feigned_mobid = feign_memory_list.begin();
|
||||||
while (RememberedCharID != feign_memory_list.end())
|
while (remembered_feigned_mobid != feign_memory_list.end())
|
||||||
{
|
{
|
||||||
Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID);
|
Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid);
|
||||||
if(remember_client != nullptr) //Still in zone
|
if (remembered_mob->IsClient() && remembered_mob != nullptr) { //Still in zone
|
||||||
remember_client->RemoveXTarget(this, false);
|
remembered_mob->CastToClient()->RemoveXTarget(this, false);
|
||||||
++RememberedCharID;
|
}
|
||||||
|
++remembered_feigned_mobid;
|
||||||
}
|
}
|
||||||
|
|
||||||
feign_memory_list.clear();
|
feign_memory_list.clear();
|
||||||
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
|
minLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMin);
|
||||||
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
|
maxLastFightingDelayMoving = RuleI(NPC, LastFightingDelayMovingMax);
|
||||||
if(AI_feign_remember_timer != nullptr)
|
if (AI_feign_remember_timer != nullptr) {
|
||||||
AI_feign_remember_timer->Disable();
|
AI_feign_remember_timer->Disable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::IsOnFeignMemory(Client *attacker) const
|
bool Mob::IsOnFeignMemory(Mob *attacker) const
|
||||||
{
|
{
|
||||||
return feign_memory_list.find(attacker->CharacterID()) != feign_memory_list.end();
|
if (!attacker) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return feign_memory_list.find(attacker->GetID()) != feign_memory_list.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
|
bool Mob::PassCharismaCheck(Mob* caster, uint16 spell_id) {
|
||||||
|
|||||||
@ -2813,7 +2813,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
|
|
||||||
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
||||||
|
|
||||||
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient()))
|
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other))
|
||||||
other->CastToClient()->AddAutoXTarget(this);
|
other->CastToClient()->AddAutoXTarget(this);
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
|
|||||||
@ -1571,8 +1571,10 @@ void Mob::ApplyAABonuses(const AA::Rank &rank, StatBonuses *newbon)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_FeignedMinion:
|
case SE_FeignedMinion:
|
||||||
if (newbon->FeignedMinionChance < base_value)
|
if (newbon->FeignedMinionChance < base_value) {
|
||||||
newbon->FeignedMinionChance = base_value;
|
newbon->FeignedMinionChance = base_value;
|
||||||
|
}
|
||||||
|
newbon->PetCommands[PET_FEIGN] = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SE_AdditionalAura:
|
case SE_AdditionalAura:
|
||||||
|
|||||||
@ -145,7 +145,6 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
global_channel_timer(1000),
|
global_channel_timer(1000),
|
||||||
fishing_timer(8000),
|
fishing_timer(8000),
|
||||||
endupkeep_timer(1000),
|
endupkeep_timer(1000),
|
||||||
forget_timer(0),
|
|
||||||
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
autosave_timer(RuleI(Character, AutosaveIntervalS) * 1000),
|
||||||
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
client_scan_npc_aggro_timer(RuleI(Aggro, ClientAggroCheckIdleInterval)),
|
||||||
client_zone_wide_full_position_update_timer(5 * 60 * 1000),
|
client_zone_wide_full_position_update_timer(5 * 60 * 1000),
|
||||||
@ -186,7 +185,6 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
character_id = 0;
|
character_id = 0;
|
||||||
conn_state = NoPacketsReceived;
|
conn_state = NoPacketsReceived;
|
||||||
client_data_loaded = false;
|
client_data_loaded = false;
|
||||||
feigned = false;
|
|
||||||
berserk = false;
|
berserk = false;
|
||||||
dead = false;
|
dead = false;
|
||||||
eqs = ieqs;
|
eqs = ieqs;
|
||||||
@ -2677,22 +2675,6 @@ void Client::MemorizeSpell(uint32 slot,uint32 spellid,uint32 scribing, uint32 re
|
|||||||
safe_delete(outapp);
|
safe_delete(outapp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SetFeigned(bool in_feigned) {
|
|
||||||
if (in_feigned)
|
|
||||||
{
|
|
||||||
if(RuleB(Character, FeignKillsPet))
|
|
||||||
{
|
|
||||||
SetPet(0);
|
|
||||||
}
|
|
||||||
SetHorseId(0);
|
|
||||||
entity_list.ClearFeignAggro(this);
|
|
||||||
forget_timer.Start(FeignMemoryDuration);
|
|
||||||
} else {
|
|
||||||
forget_timer.Disable();
|
|
||||||
}
|
|
||||||
feigned=in_feigned;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQ::ItemData* item, bool buying)
|
void Client::LogMerchant(Client* player, Mob* merchant, uint32 quantity, uint32 price, const EQ::ItemData* item, bool buying)
|
||||||
{
|
{
|
||||||
if(!player || !merchant || !item)
|
if(!player || !merchant || !item)
|
||||||
|
|||||||
@ -835,9 +835,6 @@ public:
|
|||||||
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
|
inline uint8 GetBecomeNPCLevel() const { return npclevel; }
|
||||||
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
|
inline void SetBecomeNPC(bool flag) { npcflag = flag; }
|
||||||
inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; }
|
inline void SetBecomeNPCLevel(uint8 level) { npclevel = level; }
|
||||||
void SetFeigned(bool in_feigned);
|
|
||||||
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
|
|
||||||
inline bool GetFeigned() const { return(feigned); }
|
|
||||||
EQStreamInterface* Connection() { return eqs; }
|
EQStreamInterface* Connection() { return eqs; }
|
||||||
#ifdef PACKET_PROFILER
|
#ifdef PACKET_PROFILER
|
||||||
void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
|
void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
|
||||||
@ -1850,7 +1847,6 @@ private:
|
|||||||
Timer global_channel_timer;
|
Timer global_channel_timer;
|
||||||
Timer fishing_timer;
|
Timer fishing_timer;
|
||||||
Timer endupkeep_timer;
|
Timer endupkeep_timer;
|
||||||
Timer forget_timer; // our 2 min everybody forgets you timer
|
|
||||||
Timer autosave_timer;
|
Timer autosave_timer;
|
||||||
Timer client_scan_npc_aggro_timer;
|
Timer client_scan_npc_aggro_timer;
|
||||||
Timer client_zone_wide_full_position_update_timer;
|
Timer client_zone_wide_full_position_update_timer;
|
||||||
@ -1890,7 +1886,6 @@ private:
|
|||||||
|
|
||||||
bool npcflag;
|
bool npcflag;
|
||||||
uint8 npclevel;
|
uint8 npclevel;
|
||||||
bool feigned;
|
|
||||||
bool bZoning;
|
bool bZoning;
|
||||||
bool tgb;
|
bool tgb;
|
||||||
bool instalog;
|
bool instalog;
|
||||||
|
|||||||
@ -10255,6 +10255,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
if (target != this && DistanceSquaredNoZ(mypet->GetPosition(), target->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
if (mypet->IsPetStop()) {
|
if (mypet->IsPetStop()) {
|
||||||
mypet->SetPetStop(false);
|
mypet->SetPetStop(false);
|
||||||
SetPetCommandState(PET_BUTTON_STOP, 0);
|
SetPetCommandState(PET_BUTTON_STOP, 0);
|
||||||
@ -10301,6 +10302,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
|
|
||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
if (GetTarget() != this && DistanceSquaredNoZ(mypet->GetPosition(), GetTarget()->GetPosition()) <= (RuleR(Pets, AttackCommandRange)*RuleR(Pets, AttackCommandRange))) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
if (mypet->IsPetStop()) {
|
if (mypet->IsPetStop()) {
|
||||||
mypet->SetPetStop(false);
|
mypet->SetPetStop(false);
|
||||||
SetPetCommandState(PET_BUTTON_STOP, 0);
|
SetPetCommandState(PET_BUTTON_STOP, 0);
|
||||||
@ -10376,6 +10378,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if (mypet->IsNPC()) {
|
if (mypet->IsNPC()) {
|
||||||
|
|
||||||
// Set Sit button to unpressed - send stand anim/end hpregen
|
// Set Sit button to unpressed - send stand anim/end hpregen
|
||||||
|
mypet->SetFeigned(false);
|
||||||
SetPetCommandState(PET_BUTTON_SIT, 0);
|
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||||
|
|
||||||
@ -10396,6 +10399,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||||
|
|
||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
mypet->SayString(this, Chat::PetResponse, PET_FOLLOWING);
|
mypet->SayString(this, Chat::PetResponse, PET_FOLLOWING);
|
||||||
mypet->SetPetOrder(SPO_Follow);
|
mypet->SetPetOrder(SPO_Follow);
|
||||||
|
|
||||||
@ -10443,6 +10447,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||||
|
|
||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
mypet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING);
|
mypet->SayString(this, Chat::PetResponse, PET_GUARDME_STRING);
|
||||||
mypet->SetPetOrder(SPO_Follow);
|
mypet->SetPetOrder(SPO_Follow);
|
||||||
|
|
||||||
@ -10463,12 +10468,14 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
if (mypet->GetPetOrder() == SPO_Sit)
|
if (mypet->GetPetOrder() == SPO_Sit)
|
||||||
{
|
{
|
||||||
|
mypet->SetFeigned(false);
|
||||||
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
||||||
mypet->SetPetOrder(SPO_Follow);
|
mypet->SetPetOrder(SPO_Follow);
|
||||||
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
mypet->SendAppearancePacket(AT_Anim, ANIM_STAND);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
mypet->SetFeigned(false);
|
||||||
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
||||||
mypet->SetPetOrder(SPO_Sit);
|
mypet->SetPetOrder(SPO_Sit);
|
||||||
mypet->SetRunAnimSpeed(0);
|
mypet->SetRunAnimSpeed(0);
|
||||||
@ -10483,6 +10490,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||||
|
|
||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
||||||
SetPetCommandState(PET_BUTTON_SIT, 0);
|
SetPetCommandState(PET_BUTTON_SIT, 0);
|
||||||
mypet->SetPetOrder(SPO_Follow);
|
mypet->SetPetOrder(SPO_Follow);
|
||||||
@ -10494,6 +10502,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||||
|
|
||||||
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
if ((mypet->GetPetType() == petAnimation && aabonuses.PetCommands[PetCommand]) || mypet->GetPetType() != petAnimation) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
mypet->SayString(this, Chat::PetResponse, PET_SIT_STRING);
|
||||||
SetPetCommandState(PET_BUTTON_SIT, 1);
|
SetPetCommandState(PET_BUTTON_SIT, 1);
|
||||||
mypet->SetPetOrder(SPO_Sit);
|
mypet->SetPetOrder(SPO_Sit);
|
||||||
@ -10687,6 +10696,38 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PET_FEIGN: {
|
||||||
|
if (aabonuses.PetCommands[PetCommand] && mypet->IsNPC()) {
|
||||||
|
if (mypet->IsFeared())
|
||||||
|
break;
|
||||||
|
|
||||||
|
int pet_fd_chance = aabonuses.FeignedMinionChance;
|
||||||
|
if (zone->random.Int(0, 99) > pet_fd_chance) {
|
||||||
|
mypet->SetFeigned(false);
|
||||||
|
entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, mypet->GetCleanName());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bool immune_aggro = GetSpecialAbility(IMMUNE_AGGRO);
|
||||||
|
mypet->SetSpecialAbility(IMMUNE_AGGRO, 1);
|
||||||
|
mypet->WipeHateList();
|
||||||
|
mypet->SetPetOrder(SPO_FeignDeath);
|
||||||
|
mypet->SetRunAnimSpeed(0);
|
||||||
|
mypet->StopNavigation();
|
||||||
|
mypet->SendAppearancePacket(AT_Anim, ANIM_DEATH);
|
||||||
|
mypet->SetFeigned(true);
|
||||||
|
mypet->SetTarget(nullptr);
|
||||||
|
if (!mypet->UseBardSpellLogic()) {
|
||||||
|
mypet->InterruptSpell();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!immune_aggro) {
|
||||||
|
mypet->SetSpecialAbility(IMMUNE_AGGRO, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case PET_STOP: {
|
case PET_STOP: {
|
||||||
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF
|
||||||
|
|
||||||
@ -10694,7 +10735,6 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app)
|
|||||||
if (mypet->IsPetStop()) {
|
if (mypet->IsPetStop()) {
|
||||||
mypet->SetPetStop(false);
|
mypet->SetPetStop(false);
|
||||||
} else {
|
} else {
|
||||||
mypet->SetPetStop(true);
|
|
||||||
mypet->StopNavigation();
|
mypet->StopNavigation();
|
||||||
mypet->SetTarget(nullptr);
|
mypet->SetTarget(nullptr);
|
||||||
if (mypet->IsPetRegroup()) {
|
if (mypet->IsPetRegroup()) {
|
||||||
|
|||||||
@ -1515,10 +1515,10 @@ void EntityList::RemoveFromTargets(Mob *mob, bool RemoveFromXTargets)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (RemoveFromXTargets) {
|
if (RemoveFromXTargets) {
|
||||||
if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m->CastToClient())))
|
if (m->IsClient() && (mob->CheckAggro(m) || mob->IsOnFeignMemory(m)))
|
||||||
m->CastToClient()->RemoveXTarget(mob, false);
|
m->CastToClient()->RemoveXTarget(mob, false);
|
||||||
// FadingMemories calls this function passing the client.
|
// FadingMemories calls this function passing the client.
|
||||||
else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob->CastToClient())))
|
else if (mob->IsClient() && (m->CheckAggro(mob) || m->IsOnFeignMemory(mob)))
|
||||||
mob->CastToClient()->RemoveXTarget(m, false);
|
mob->CastToClient()->RemoveXTarget(m, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3488,7 +3488,7 @@ void EntityList::ClearFeignAggro(Mob *targ)
|
|||||||
auto it = npc_list.begin();
|
auto it = npc_list.begin();
|
||||||
while (it != npc_list.end()) {
|
while (it != npc_list.end()) {
|
||||||
// add Feign Memory check because sometimes weird stuff happens
|
// add Feign Memory check because sometimes weird stuff happens
|
||||||
if (it->second->CheckAggro(targ) || (targ->IsClient() && it->second->IsOnFeignMemory(targ->CastToClient()))) {
|
if (it->second->CheckAggro(targ) || (targ->IsClient() && it->second->IsOnFeignMemory(targ))) {
|
||||||
if (it->second->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) {
|
if (it->second->GetSpecialAbility(IMMUNE_FEIGN_DEATH)) {
|
||||||
++it;
|
++it;
|
||||||
continue;
|
continue;
|
||||||
@ -3514,22 +3514,31 @@ void EntityList::ClearFeignAggro(Mob *targ)
|
|||||||
|
|
||||||
it->second->RemoveFromHateList(targ);
|
it->second->RemoveFromHateList(targ);
|
||||||
if (targ->IsClient()) {
|
if (targ->IsClient()) {
|
||||||
if (it->second->GetLevel() >= 35 && zone->random.Roll(60))
|
if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) {
|
||||||
it->second->AddFeignMemory(targ->CastToClient());
|
it->second->AddFeignMemory(targ);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
targ->CastToClient()->RemoveXTarget(it->second, false);
|
targ->CastToClient()->RemoveXTarget(it->second, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (targ->IsPet()){
|
||||||
|
if (it->second->GetLevel() >= 35 && zone->random.Roll(60)) {
|
||||||
|
it->second->AddFeignMemory(targ);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityList::ClearZoneFeignAggro(Client *targ)
|
void EntityList::ClearZoneFeignAggro(Mob *targ)
|
||||||
{
|
{
|
||||||
auto it = npc_list.begin();
|
auto it = npc_list.begin();
|
||||||
while (it != npc_list.end()) {
|
while (it != npc_list.end()) {
|
||||||
it->second->RemoveFromFeignMemory(targ);
|
it->second->RemoveFromFeignMemory(targ);
|
||||||
targ->CastToClient()->RemoveXTarget(it->second, false);
|
if (targ && targ->IsClient()) {
|
||||||
|
targ->CastToClient()->RemoveXTarget(it->second, false);
|
||||||
|
}
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -455,7 +455,7 @@ public:
|
|||||||
void ClearAggro(Mob* targ);
|
void ClearAggro(Mob* targ);
|
||||||
void ClearWaterAggro(Mob* targ);
|
void ClearWaterAggro(Mob* targ);
|
||||||
void ClearFeignAggro(Mob* targ);
|
void ClearFeignAggro(Mob* targ);
|
||||||
void ClearZoneFeignAggro(Client* targ);
|
void ClearZoneFeignAggro(Mob* targ);
|
||||||
void AggroZone(Mob* who, uint32 hate = 0);
|
void AggroZone(Mob* who, uint32 hate = 0);
|
||||||
|
|
||||||
bool Fighting(Mob* targ);
|
bool Fighting(Mob* targ);
|
||||||
|
|||||||
21
zone/mob.cpp
21
zone/mob.cpp
@ -109,6 +109,7 @@ Mob::Mob(
|
|||||||
stunned_timer(0),
|
stunned_timer(0),
|
||||||
spun_timer(0),
|
spun_timer(0),
|
||||||
bardsong_timer(6000),
|
bardsong_timer(6000),
|
||||||
|
forget_timer(0),
|
||||||
gravity_timer(1000),
|
gravity_timer(1000),
|
||||||
viral_timer(0),
|
viral_timer(0),
|
||||||
m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f),
|
m_FearWalkTarget(-999999.0f, -999999.0f, -999999.0f),
|
||||||
@ -282,6 +283,8 @@ Mob::Mob(
|
|||||||
|
|
||||||
InitializeBuffSlots();
|
InitializeBuffSlots();
|
||||||
|
|
||||||
|
feigned = false;
|
||||||
|
|
||||||
// clear the proc arrays
|
// clear the proc arrays
|
||||||
for (int j = 0; j < MAX_PROCS; j++) {
|
for (int j = 0; j < MAX_PROCS; j++) {
|
||||||
PermaProcs[j].spellID = SPELL_UNKNOWN;
|
PermaProcs[j].spellID = SPELL_UNKNOWN;
|
||||||
@ -6505,6 +6508,24 @@ void Mob::ShieldAbilityClearVariables()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::SetFeigned(bool in_feigned) {
|
||||||
|
|
||||||
|
if (in_feigned) {
|
||||||
|
if (IsClient()) {
|
||||||
|
if (RuleB(Character, FeignKillsPet)){
|
||||||
|
SetPet(0);
|
||||||
|
}
|
||||||
|
CastToClient()->SetHorseId(0);
|
||||||
|
}
|
||||||
|
entity_list.ClearFeignAggro(this);
|
||||||
|
forget_timer.Start(FeignMemoryDuration);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
forget_timer.Disable();
|
||||||
|
}
|
||||||
|
feigned = in_feigned;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
bool Mob::JoinHealRotationTargetPool(std::shared_ptr<HealRotation>* heal_rotation)
|
bool Mob::JoinHealRotationTargetPool(std::shared_ptr<HealRotation>* heal_rotation)
|
||||||
{
|
{
|
||||||
|
|||||||
15
zone/mob.h
15
zone/mob.h
@ -71,7 +71,7 @@ class Mob : public Entity {
|
|||||||
public:
|
public:
|
||||||
enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD,
|
enum CLIENT_CONN_STATUS { CLIENT_CONNECTING, CLIENT_CONNECTED, CLIENT_LINKDEAD,
|
||||||
CLIENT_KICKED, DISCONNECTED, CLIENT_ERROR, CLIENT_CONNECTINGALL };
|
CLIENT_KICKED, DISCONNECTED, CLIENT_ERROR, CLIENT_CONNECTINGALL };
|
||||||
enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard };
|
enum eStandingPetOrder { SPO_Follow, SPO_Sit, SPO_Guard, SPO_FeignDeath };
|
||||||
|
|
||||||
struct SpecialAbility {
|
struct SpecialAbility {
|
||||||
SpecialAbility() {
|
SpecialAbility() {
|
||||||
@ -670,10 +670,10 @@ public:
|
|||||||
bool HateSummon();
|
bool HateSummon();
|
||||||
void FaceTarget(Mob* mob_to_face = 0);
|
void FaceTarget(Mob* mob_to_face = 0);
|
||||||
void WipeHateList();
|
void WipeHateList();
|
||||||
void AddFeignMemory(Client* attacker);
|
void AddFeignMemory(Mob* attacker);
|
||||||
void RemoveFromFeignMemory(Client* attacker);
|
void RemoveFromFeignMemory(Mob* attacker);
|
||||||
void ClearFeignMemory();
|
void ClearFeignMemory();
|
||||||
bool IsOnFeignMemory(Client *attacker) const;
|
bool IsOnFeignMemory(Mob *attacker) const;
|
||||||
void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); }
|
void PrintHateListToClient(Client *who) { hate_list.PrintHateListToClient(who); }
|
||||||
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
|
std::list<struct_HateList*>& GetHateList() { return hate_list.GetHateList(); }
|
||||||
std::list<struct_HateList*> GetHateListByDistance(int distance = 0) { return hate_list.GetHateListByDistance(distance); }
|
std::list<struct_HateList*> GetHateListByDistance(int distance = 0) { return hate_list.GetHateListByDistance(distance); }
|
||||||
@ -1296,6 +1296,10 @@ public:
|
|||||||
bool CanOpenDoors() const;
|
bool CanOpenDoors() const;
|
||||||
void SetCanOpenDoors(bool can_open);
|
void SetCanOpenDoors(bool can_open);
|
||||||
|
|
||||||
|
void SetFeigned(bool in_feigned);
|
||||||
|
/// this cures timing issues cuz dead animation isn't done but server side feigning is?
|
||||||
|
inline bool GetFeigned() const { return(feigned); }
|
||||||
|
|
||||||
void DeleteBucket(std::string bucket_name);
|
void DeleteBucket(std::string bucket_name);
|
||||||
std::string GetBucket(std::string bucket_name);
|
std::string GetBucket(std::string bucket_name);
|
||||||
std::string GetBucketExpires(std::string bucket_name);
|
std::string GetBucketExpires(std::string bucket_name);
|
||||||
@ -1720,6 +1724,9 @@ protected:
|
|||||||
AuraMgr aura_mgr;
|
AuraMgr aura_mgr;
|
||||||
AuraMgr trap_mgr;
|
AuraMgr trap_mgr;
|
||||||
|
|
||||||
|
bool feigned;
|
||||||
|
Timer forget_timer; // our 2 min everybody forgets you timer
|
||||||
|
|
||||||
bool m_can_open_doors;
|
bool m_can_open_doors;
|
||||||
|
|
||||||
MobMovementManager *mMovementManager;
|
MobMovementManager *mMovementManager;
|
||||||
|
|||||||
@ -838,20 +838,21 @@ void Client::AI_Process()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(AI_feign_remember_timer->Check()) {
|
if(AI_feign_remember_timer->Check()) {
|
||||||
std::set<uint32>::iterator RememberedCharID;
|
std::set<uint32>::iterator remembered_feigned_mobid;
|
||||||
RememberedCharID = feign_memory_list.begin();
|
remembered_feigned_mobid = feign_memory_list.begin();
|
||||||
while (RememberedCharID != feign_memory_list.end()) {
|
while (remembered_feigned_mobid != feign_memory_list.end()) {
|
||||||
Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID);
|
|
||||||
if (remember_client == nullptr) {
|
Mob* remembered_mob = entity_list.GetMob(*remembered_feigned_mobid);
|
||||||
|
if (remembered_mob == nullptr || remembered_mob->IsCorpse()) {
|
||||||
//they are gone now...
|
//they are gone now...
|
||||||
RememberedCharID = feign_memory_list.erase(RememberedCharID);
|
remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid);
|
||||||
} else if (!remember_client->GetFeigned()) {
|
} else if (!remembered_mob->GetFeigned()) {
|
||||||
AddToHateList(remember_client->CastToMob(),1);
|
AddToHateList(remembered_mob,1);
|
||||||
RememberedCharID = feign_memory_list.erase(RememberedCharID);
|
remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid);
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
//they are still feigned, carry on...
|
//they are still feigned, carry on...
|
||||||
++RememberedCharID;
|
++remembered_feigned_mobid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1373,22 +1374,22 @@ void Mob::AI_Process() {
|
|||||||
// 6/14/06
|
// 6/14/06
|
||||||
// Improved Feign Death Memory
|
// Improved Feign Death Memory
|
||||||
// check to see if any of our previous feigned targets have gotten up.
|
// check to see if any of our previous feigned targets have gotten up.
|
||||||
std::set<uint32>::iterator RememberedCharID;
|
std::set<uint32>::iterator remembered_feigned_mobid;
|
||||||
RememberedCharID = feign_memory_list.begin();
|
remembered_feigned_mobid = feign_memory_list.begin();
|
||||||
while (RememberedCharID != feign_memory_list.end()) {
|
while (remembered_feigned_mobid != feign_memory_list.end()) {
|
||||||
Client *remember_client = entity_list.GetClientByCharID(*RememberedCharID);
|
Mob *remembered_mob = entity_list.GetMob(*remembered_feigned_mobid);
|
||||||
if (remember_client == nullptr) {
|
if (remembered_mob == nullptr || remembered_mob->IsCorpse()) {
|
||||||
//they are gone now...
|
//they are gone now...
|
||||||
RememberedCharID = feign_memory_list.erase(RememberedCharID);
|
remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid);
|
||||||
}
|
}
|
||||||
else if (!remember_client->GetFeigned()) {
|
else if (!remembered_mob->GetFeigned()) {
|
||||||
AddToHateList(remember_client->CastToMob(), 1);
|
AddToHateList(remembered_mob, 1);
|
||||||
RememberedCharID = feign_memory_list.erase(RememberedCharID);
|
remembered_feigned_mobid = feign_memory_list.erase(remembered_feigned_mobid);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//they are still feigned, carry on...
|
//they are still feigned, carry on...
|
||||||
++RememberedCharID;
|
++remembered_feigned_mobid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1485,6 +1486,10 @@ void Mob::AI_Process() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SPO_FeignDeath: {
|
||||||
|
SetAppearance(eaDead, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (IsPetRegroup()) {
|
if (IsPetRegroup()) {
|
||||||
return;
|
return;
|
||||||
@ -1557,6 +1562,11 @@ void Mob::AI_Process() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (forget_timer.Check()) {
|
||||||
|
forget_timer.Disable();
|
||||||
|
entity_list.ClearZoneFeignAggro(this);
|
||||||
|
}
|
||||||
|
|
||||||
//Do Ranged attack here
|
//Do Ranged attack here
|
||||||
if (doranged) {
|
if (doranged) {
|
||||||
RangedAttack(target);
|
RangedAttack(target);
|
||||||
|
|||||||
@ -1557,18 +1557,17 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
#ifdef SPELL_EFFECT_SPAM
|
#ifdef SPELL_EFFECT_SPAM
|
||||||
snprintf(effect_desc, _EDLEN, "Feign Death");
|
snprintf(effect_desc, _EDLEN, "Feign Death");
|
||||||
#endif
|
#endif
|
||||||
//todo, look up spell ID in DB
|
if(spell_id == SPELL_LIFEBURN) //Dook- Lifeburn fix
|
||||||
if(spell_id == 2488) //Dook- Lifeburn fix
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if(IsClient()) {
|
if(IsClient()) {
|
||||||
CastToClient()->SetHorseId(0); // dismount if have horse
|
CastToClient()->SetHorseId(0); // dismount if have horse
|
||||||
|
|
||||||
if (zone->random.Int(0, 99) > spells[spell_id].base_value[i]) {
|
if (zone->random.Int(0, 99) > spells[spell_id].base_value[i]) {
|
||||||
CastToClient()->SetFeigned(false);
|
SetFeigned(false);
|
||||||
entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, GetName());
|
entity_list.MessageCloseString(this, false, 200, 10, STRING_FEIGNFAILED, GetName());
|
||||||
} else {
|
} else {
|
||||||
CastToClient()->SetFeigned(true);
|
SetFeigned(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user