From 23820a369e32fac92d44bedf8de73151127612e3 Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Sun, 24 Mar 2013 18:08:03 -0400 Subject: [PATCH 1/5] Moved around some data in Mercs to help prevent another crash... dunno if it actually will fix it but it can't hurt >_< --- zone/merc.cpp | 6 ++---- zone/merc.h | 2 -- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/zone/merc.cpp b/zone/merc.cpp index 7fe95e4b4..a91593cbd 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -50,7 +50,6 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading) _lost_confidence = false; _hatedCount = 0; - ourNPCData = d; memset(equipment, 0, sizeof(equipment)); SetMercID(0); @@ -74,7 +73,6 @@ Merc::Merc(const NPCType* d, float x, float y, float z, float heading) Merc::~Merc() { AI_Stop(); - safe_delete(ourNPCData); //Since mercs are dynamically alloc'd we should probably safe_delete the data they were made from. I'm not entirely sure this is safe to delete a const. entity_list.RemoveMerc(this->GetID()); UninitializeBuffSlots(); } @@ -1915,9 +1913,9 @@ void Merc::AI_Start(int32 iMoveDelay) { AIautocastspell_timer->Start(RandomTimer(0, 2000), false); } - if (ourNPCData) { + if (NPCTypedata_ours) { //AI_AddNPCSpells(ourNPCData->npc_spells_id); - NPCSpecialAttacks(ourNPCData->npc_attacks,0); + NPCSpecialAttacks(NPCTypedata_ours->npc_attacks,0); } SendTo(GetX(), GetY(), GetZ()); diff --git a/zone/merc.h b/zone/merc.h index b76bb566d..dadba3fc1 100644 --- a/zone/merc.h +++ b/zone/merc.h @@ -379,8 +379,6 @@ private: bool _lost_confidence; int _hatedCount; uint32 owner_char_id; - const NPCType* ourNPCData; - Timer endupkeep_timer; Timer rest_timer; Timer confidence_timer; From c7ff207017a6c882e2578aa55aded886cb90b024 Mon Sep 17 00:00:00 2001 From: SecretsOTheP Date: Mon, 25 Mar 2013 13:07:58 -0400 Subject: [PATCH 2/5] Made Merc::AddMercToGroup handle cleaning up old groups as opposed to doing it in each location before AddMercToGroup. This should fix cases where the Merc's owner is invalid and being referenced, which causes the crash located in: http://www.eqemulator.org/forums/showthread.php?t=36670&page=2 --- zone/client_packet.cpp | 21 ++++++++------------- zone/merc.cpp | 13 ++++++------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index bc74cc148..c29f9d9b9 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -6459,15 +6459,6 @@ void Client::Handle_OP_GroupFollow2(const EQApplicationPacket *app) } } - // Remove the merc from the old group - if (GetMerc()) - { - if(GetMerc()->GetGroup()) - { - Merc::RemoveMercFromGroup(GetMerc(), GetMerc()->GetGroup()); - } - } - Group* group = entity_list.GetGroupByClient(inviter->CastToClient()); if(!group){ @@ -6539,8 +6530,9 @@ void Client::Handle_OP_GroupFollow2(const EQApplicationPacket *app) // Add the merc back into the new group if (GetMerc()) { - if (GetMerc()->AddMercToGroup(GetMerc(), group)) { + if (Merc::AddMercToGroup(GetMerc(), group)) { database.SetGroupID(GetMerc()->GetName(), group->GetID(), inviter->CastToClient()->CharacterID(), true); + database.RefreshGroupFromDB(this); } } @@ -6667,8 +6659,6 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app) Merc* memberMerc = memberToDisband->CastToClient()->GetMerc(); if(memberClient && memberMerc && group) { - Merc::RemoveMercFromGroup(memberMerc, group); - if(!memberMerc->IsGrouped() && !memberClient->IsGrouped()) { Group *g = new Group(memberClient); @@ -6713,13 +6703,18 @@ void Client::Handle_OP_GroupDisband(const EQApplicationPacket *app) return; } - if(GetMerc()->AddMercToGroup(GetMerc(), g)) { + if(Merc::AddMercToGroup(GetMerc(), g)) { database.SetGroupLeaderName(g->GetID(), this->GetName()); g->SaveGroupLeaderAA(); database.SetGroupID(this->GetName(), g->GetID(), this->CharacterID()); database.SetGroupID(GetMerc()->GetName(), g->GetID(), this->CharacterID(), true); database.RefreshGroupFromDB(this); } + else + { + if(GetMerc()) + GetMerc()->Depop(); + } } } } diff --git a/zone/merc.cpp b/zone/merc.cpp index a91593cbd..077b48cc7 100644 --- a/zone/merc.cpp +++ b/zone/merc.cpp @@ -5839,16 +5839,15 @@ bool Merc::AddMercToGroup(Merc* merc, Group* group) { if(merc->HasGroup()) { Merc::RemoveMercFromGroup(merc, merc->GetGroup()); } - // Add merc to this group - if(group->AddMember(merc)) { - merc->SetFollowID(merc->GetMercOwner()->GetID()); - Result = true; + //Try and add the member, followed by checking if the merc owner exists. + if(group->AddMember(merc) && merc->GetMercOwner() != NULL) { + merc->SetFollowID(merc->GetMercOwner()->GetID()); + Result = true; } - else - { + else { + //Suspend it if the member is not added and the merc's owner is not valid. merc->Suspend(); } - } return Result; From 96b42ed86f4c38ee43ca15b7335b772f78172bc4 Mon Sep 17 00:00:00 2001 From: mackal Date: Sat, 30 Mar 2013 22:57:20 -0400 Subject: [PATCH 3/5] Fix pet message to use StringIDs, most should be correct related to pet "saying" or just the client getting a message Added the pet taunting message --- changelog.txt | 3 +++ zone/StringIDs.h | 9 +++++++++ zone/attack.cpp | 6 ++++-- zone/client_packet.cpp | 28 ++++++++++++---------------- zone/special_attacks.cpp | 1 + 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/changelog.txt b/changelog.txt index b58111ee8..59b7a4e02 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,9 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 03/30/2013 == +demonstar55: Fixed most of the pet talking, all use StringIDs now. Pet now informs you when it taunts. + == 03/23/2013 == demonstar55: Fix issues with escape not always working and fixed SE_FadingMemories to have the message since the message isn't part of the spell data. Escape now uses just the spell and not the AA Actoin diff --git a/zone/StringIDs.h b/zone/StringIDs.h index d95245b62..ba811ff90 100644 --- a/zone/StringIDs.h +++ b/zone/StringIDs.h @@ -125,6 +125,7 @@ #define OTHER_HIT_NONMELEE 434 //%1 was hit by non-melee for %2 points of damage. #define SPELL_WORN_OFF_OF 436 //Your %1 spell has worn off of %2. #define SPELL_WORN_OFF 437 //Your %1 spell has worn off. +#define PET_TAUNTING 438 //Taunting attacker, Master. #define INTERRUPT_SPELL 439 //Your spell is interrupted. #define LOSE_LEVEL 442 //You LOST a level! You are now level %1! #define GAIN_ABILITY_POINT 446 //You have gained an ability point! You now have %1 ability point%2. @@ -137,6 +138,8 @@ #define FACTION_BEST 471 //Your faction standing with %1 could not possibly get any better. #define FACTION_BETTER 472 //Your faction standing with %1 got better. #define PET_REPORT_HP 488 //I have %1 percent of my hit points left. +#define PET_NO_TAUNT 489 //No longer taunting attackers, Master. +#define PET_DO_TAUNT 490 //Taunting attackers as normal, Master. #define CORPSE_DECAY1 495 //This corpse will decay in %1 minute(s) %2 seconds. #define DISC_LEVEL_ERROR 503 //You must be a level %1 ... to use this discipline. #define DISCIPLINE_CANUSEIN 504 //You can use a new discipline in %1 minutes %2 seconds. @@ -176,6 +179,8 @@ #define PET_GETLOST_STRING 1135 //As you wish, oh great one. #define PET_LEADERIS 1136 //My leader is %3. #define I_FOLLOW_NOONE 1137 //I follow no one. +#define PET_ON_HOLD 1138 //Waiting for your order to attack, Master. +#define NOT_LEGAL_TARGET 1139 //I beg forgiveness, Master. That is not a legal target. #define MERCHANT_BUSY 1143 //I'm sorry, I am busy right now. #define MERCHANT_GREETING 1144 //Welcome to my shop, %3. #define MERCHANT_HANDY_ITEM1 1145 //Hello there, %3. How about a nice %4? @@ -273,6 +278,10 @@ #define STRIKETHROUGH_STRING 9078 //You strike through your opponent's defenses! #define SPELL_REFLECT 9082 //%1's spell has been reflected by %2. #define NEW_SPELLS_AVAIL 9149 //You have new spells available to you. Check the merchants near your guild master. +#define PET_NOW_FOCUSING 9254 //Focusing on one target, Master. +#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 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. diff --git a/zone/attack.cpp b/zone/attack.cpp index 141aa50ec..66d08c6b3 100644 --- a/zone/attack.cpp +++ b/zone/attack.cpp @@ -1707,8 +1707,10 @@ bool NPC::Attack(Mob* other, int Hand, bool bRiposte, bool IsStrikethrough, bool //Check that we can attack before we calc heading and face our target if (!IsAttackAllowed(other)) { if (this->GetOwnerID()) - entity_list.MessageClose(this, 1, 200, 10, "%s says, 'That is not a legal target master.'", this->GetCleanName()); + this->Say_StringID(NOT_LEGAL_TARGET); if(other) { + if (other->IsClient()) + other->CastToClient()->RemoveXTarget(this, false); RemoveFromHateList(other); mlog(COMBAT__ATTACKS, "I am not allowed to attack %s", other->GetName()); } @@ -4332,4 +4334,4 @@ int32 Mob::RuneAbsorb(int32 damage, uint16 type) } return damage; } -} \ No newline at end of file +} diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index c29f9d9b9..52d35dd71 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -7077,7 +7077,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) } zone->AddAggroMob(); mypet->AddToHateList(GetTarget(), 1); - Message_StringID(10, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); + Message_StringID(MT_PetResponse, PET_ATTACKING, mypet->GetCleanName(), GetTarget()->GetCleanName()); } } break; @@ -7093,7 +7093,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) break; } case PET_HEALTHREPORT: { - Message_StringID(10, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1)); + Message_StringID(MT_PetResponse, PET_REPORT_HP, ConvertArrayF(mypet->GetHPRatio(), val1)); mypet->ShowBuffList(this); //Message(10,"%s tells you, 'I have %d percent of my hit points left.'",mypet->GetName(),(uint8)mypet->GetHPRatio()); break; @@ -7150,14 +7150,14 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) } case PET_TAUNT: { if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) { - Message(0,"%s says, 'Now taunting foes, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_DO_TAUNT); mypet->CastToNPC()->SetTaunting(true); } break; } case PET_NOTAUNT: { if((mypet->GetPetType() == petAnimation && GetAA(aaAnimationEmpathy) >= 3) || mypet->GetPetType() != petAnimation) { - Message(0,"%s says, 'No longer taunting foes, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_NO_TAUNT); mypet->CastToNPC()->SetTaunting(false); } break; @@ -7214,7 +7214,7 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; //could be exploited like PET_BACKOFF - mypet->Say("I will hold until given an order, master."); + mypet->Say_StringID(PET_ON_HOLD); mypet->WipeHateList(); mypet->SetHeld(true); } @@ -7225,10 +7225,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; if (mypet->IsNoCast()) { - Message(0,"%s says, 'I will now cast spells, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_CASTING); mypet->CastToNPC()->SetNoCast(false); } else { - Message(0,"%s says, 'I will no longer cast spells, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_NOT_CASTING); mypet->CastToNPC()->SetNoCast(true); } } @@ -7239,10 +7239,10 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; if (mypet->IsFocused()) { - Message(0,"%s says, 'I am no longer focused, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_NOT_FOCUSING); mypet->CastToNPC()->SetFocused(false); } else { - Message(0,"%s says, 'I will now focus my attention, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_NOW_FOCUSING); mypet->CastToNPC()->SetFocused(true); } } @@ -7252,10 +7252,8 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if(GetAA(aaAdvancedPetDiscipline) >= 1 && mypet->IsNPC()) { if (mypet->IsFeared()) break; - if (mypet->IsFocused()) { - Message(0,"%s says, 'I am already focused, Master!",mypet->GetCleanName()); - } else { - Message(0,"%s says, 'I will now focus my attention, Master!",mypet->GetCleanName()); + if (!mypet->IsFocused()) { + Message_StringID(MT_PetResponse, PET_NOW_FOCUSING); mypet->CastToNPC()->SetFocused(true); } } @@ -7266,10 +7264,8 @@ void Client::Handle_OP_PetCommands(const EQApplicationPacket *app) if (mypet->IsFeared()) break; if (mypet->IsFocused()) { - Message(0,"%s says, 'I am no longer focused, Master!",mypet->GetCleanName()); + Message_StringID(MT_PetResponse, PET_NOT_FOCUSING); mypet->CastToNPC()->SetFocused(false); - } else { - Message(0,"%s says, 'I am already not focused, Master!",mypet->GetCleanName()); } } break; diff --git a/zone/special_attacks.cpp b/zone/special_attacks.cpp index 8d0a33ca0..1560e5592 100644 --- a/zone/special_attacks.cpp +++ b/zone/special_attacks.cpp @@ -1397,6 +1397,7 @@ void NPC::DoClassAttacks(Mob *target) { //general stuff, for all classes.... //only gets used when their primary ability get used too if (taunting && HasOwner() && target->IsNPC() && target->GetBodyType() != BT_Undead && taunt_time) { + this->GetOwner()->Message_StringID(MT_PetResponse, PET_TAUNTING); Taunt(target->CastToNPC(), false); } From 353d7cede0173c50026e594cbd4a8cc114490dc0 Mon Sep 17 00:00:00 2001 From: mackal Date: Mon, 1 Apr 2013 17:19:45 -0400 Subject: [PATCH 4/5] Bards can now use instant cast AAs while singing (Fading Memories, Boastful Bellow) AA reuse timers now start before the spell is cast and reset upon failure or canceling --- changelog.txt | 4 ++++ zone/AA.cpp | 28 ++++++++++++++++++++++------ zone/StringIDs.h | 1 + zone/spells.cpp | 22 ++++++++++------------ 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/changelog.txt b/changelog.txt index 59b7a4e02..07c89cf11 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,10 @@ EQEMu Changelog (Started on Sept 24, 2003 15:50) ------------------------------------------------------- +== 04/01/2013 == +demonstar55: AA reuse timers now start when you hit the button and are reset upon failure +demonstar55: Instant Cast bard AAs can now be used while singing a song + == 03/30/2013 == demonstar55: Fixed most of the pet talking, all use StringIDs now. Pet now informs you when it taunts. diff --git a/zone/AA.cpp b/zone/AA.cpp index fdf5d6a95..05ffbb862 100644 --- a/zone/AA.cpp +++ b/zone/AA.cpp @@ -257,7 +257,7 @@ void Client::ActivateAA(aaID activate){ if(caa->action != aaActionNone) { if(caa->mana_cost > 0) { if(GetMana() < caa->mana_cost) { - Message(0, "Not enough mana to use this skill."); + Message_StringID(13, INSUFFICIENT_MANA); return; } SetMana(GetMana() - caa->mana_cost); @@ -271,8 +271,7 @@ void Client::ActivateAA(aaID activate){ p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime); } p_timers.Start(AATimerID + pTimerAAStart, timer_base); - time_t timestamp = time(NULL); - SendAATimer(AATimerID, static_cast(timestamp), static_cast(timestamp)); + SendAATimer(AATimerID, 0, 0); } } @@ -282,13 +281,30 @@ void Client::ActivateAA(aaID activate){ if(caa->reuse_time > 0) { uint32 timer_base = CalcAAReuseTimer(caa); + SendAATimer(AATimerID, 0, 0); + p_timers.Start(AATimerID + pTimerAAStart, timer_base); if(activate == aaImprovedHarmTouch || activate == aaLeechTouch) { p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime); } - - if(!CastSpell(caa->spell_id, target_id, 10, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) - return; + // Bards can cast instant cast AAs while they are casting another song + if (spells[caa->spell_id].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) { + if(!SpellFinished(caa->spell_id, entity_list.GetMob(target_id), 10, -1, -1, spells[caa->spell_id].ResistDiff, false)) { + //Reset on failed cast + SendAATimer(AATimerID, 0, 0xFFFFFF); + Message_StringID(15,ABILITY_FAILED); + p_timers.Clear(&database, AATimerID + pTimerAAStart); + return; + } + } else { + if(!CastSpell(caa->spell_id, target_id, 10, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) { + //Reset on failed cast + SendAATimer(AATimerID, 0, 0xFFFFFF); + Message_StringID(15,ABILITY_FAILED); + p_timers.Clear(&database, AATimerID + pTimerAAStart); + return; + } + } } else { diff --git a/zone/StringIDs.h b/zone/StringIDs.h index ba811ff90..6c44203b1 100644 --- a/zone/StringIDs.h +++ b/zone/StringIDs.h @@ -10,6 +10,7 @@ #define SPELL_DOES_NOT_WORK_PLANE 107 //This spell does not work on this plane. #define CANT_SEE_TARGET 108 //You cannot see your target. #define MGB_STRING 113 //The next group buff you cast will hit all targets in range. +#define ABILITY_FAILED 116 //Your ability failed. Timer has been reset. #define ESCAPE 114 //You escape from combat, hiding yourself from view. #define TARGET_TOO_FAR 124 //Your target is too far away, get closer! #define PROC_TOOLOW 126 //Your will is not sufficient to command this weapon. diff --git a/zone/spells.cpp b/zone/spells.cpp index 5c85b4445..6ff8bb3b8 100644 --- a/zone/spells.cpp +++ b/zone/spells.cpp @@ -707,23 +707,26 @@ void Mob::InterruptSpell(uint16 message, uint16 color, uint16 spellid) CastToNPC()->AI_Event_SpellCastFinished(false, casting_spell_slot); } - if(casting_spell_type == 1 && IsClient()) //Rest AA Timer on failed cast - CastToClient()->GetPTimers().Clear(&database, casting_spell_timer); - + if(casting_spell_type == 1 && IsClient()) { //Rest AA Timer on failed cast + CastToClient()->SendAATimer(casting_spell_timer - pTimerAAStart, 0, 0xFFFFFF); + CastToClient()->Message_StringID(15,ABILITY_FAILED); + CastToClient()->GetPTimers().Clear(&database, casting_spell_timer); + } + ZeroCastingVars(); // resets all the state keeping stuff - + mlog(SPELLS__CASTING, "Spell %d has been interrupted.", spellid); - + if(!spellid) return; - + if (bardsong || IsBardSong(casting_spell_id)) _StopSong(); if(bard_song_mode) { return; } - + if(!message) message = IsBardSong(spellid) ? SONG_ENDS_ABRUPTLY : INTERRUPT_SPELL; @@ -1971,11 +1974,6 @@ bool Mob::SpellFinished(uint16 spell_id, Mob *spell_target, uint16 slot, uint16 { CastToClient()->GetPTimers().Start(casting_spell_timer, casting_spell_timer_duration); mlog(SPELLS__CASTING, "Spell %d: Setting custom reuse timer %d to %d", spell_id, casting_spell_timer, casting_spell_timer_duration); - if(casting_spell_type == 1) //AA - { - time_t timestamp = time(NULL); - CastToClient()->SendAATimer((casting_spell_timer - pTimerAAStart), timestamp, timestamp); - } } else if(spells[spell_id].recast_time > 1000) { int recast = spells[spell_id].recast_time/1000; From 757fc01b781d1ca9370fb086d39ae22a0fba0485 Mon Sep 17 00:00:00 2001 From: KimLS Date: Mon, 1 Apr 2013 14:23:54 -0700 Subject: [PATCH 5/5] Patch for: -Perl blessing of exported variables is causing the SVs to be overwritten but never freed by the Perl GC. I'm not sure if this is a feature or a bug in Perl as the documentation sucks. Addressed by setting the blessed SVs in question to be undefined at the end of every script. Caused a noticeable drop in memory for zones with a lot of quest events firing but it's probably not perfect. --- zone/perlparser.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/zone/perlparser.cpp b/zone/perlparser.cpp index 148e50154..871551b10 100644 --- a/zone/perlparser.cpp +++ b/zone/perlparser.cpp @@ -158,6 +158,14 @@ void PerlXSParser::SendCommands(const char * pkgprefix, const char *event, uint3 //now call the requested sub perl->dosub(std::string(pkgprefix).append("::").append(event).c_str()); +#ifdef EMBPERL_XS_CLASSES + std::string eval_str = (std::string)"$" + (std::string)pkgprefix + (std::string)"::client = undef;"; + eval_str += (std::string)"$" + (std::string)pkgprefix + (std::string)"::npc = undef;"; + eval_str += (std::string)"$" + (std::string)pkgprefix + (std::string)"::questitem = undef;"; + eval_str += (std::string)"$" + (std::string)pkgprefix + (std::string)"::entity_list = undef;"; + perl->eval(eval_str.c_str()); +#endif + } catch(const char * err) { //try to reduce some of the console spam...