EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Server Code Submissions (https://www.eqemulator.org/forums/forumdisplay.php?f=669)
-   -   COMMITTED: Suspend Minion Patch (https://www.eqemulator.org/forums/showthread.php?t=30311)

blmille2 01-16-2010 02:12 AM

I'll code it to be that if the pet is on any hate list that you can't suspend him.

I could resort to looking to see if he's at the top of the list.

Let me know how live works.

Thanks so much for doing the homework!

blmille2 01-16-2010 02:47 AM

Here it is!
 
Okay, so here it is!

Suspend Minion functionality:
- Rank 1 = ability to suspend minion WITHOUT spells OR equipment
- Rank 2 = ability to suspend minion WITH spells AND equipment

Limitations:
- Pet must not be fighting something
- Pet must not be on any aggro list
- Suspended minion will poof upon leaving zone by any means (i.e. zone/log/etc.)
- You cannot suspend more than one minion
- You cannot unsuspend if you have a pet active.

Code:

Index: zone/AA.h
===================================================================
--- zone/AA.h        (revision 1094)
+++ zone/AA.h        (working copy)
@@ -265,6 +265,7 @@
        aaParagonofSpirit = 291,                        //DB
        aaAdvancedInnateStrength = 292,                //works
        aaAdvancedInnateStamina = 302,                //works
+        //aaSuspendMinion = 308,                                //WIP -- brandon
        aaAdvancedInnateAgility = 312,                //works
        aaAdvancedInnateDexterity = 322,        //works
        aaAdvancedInnateIntelligence = 332, //works
Index: zone/aggro.cpp
===================================================================
--- zone/aggro.cpp        (revision 1094)
+++ zone/aggro.cpp        (working copy)
@@ -31,6 +31,20 @@
 extern Zone* zone;
 //#define LOSDEBUG 6
 
+bool Mob::HasAggro(){
+        bool hasAggro = false;
+       
+        list<NPC*> npc_list = entity_list.GetNPCList();
+        list<NPC*>::iterator iter;
+        iter = npc_list.begin();
+        while(iter != npc_list.end() && !hasAggro)
+        {
+                hasAggro |= (*iter)->CheckAggro(this);
+                iter++;
+        }
+        return hasAggro;
+}
+
 //look around a client for things which might aggro the client.
 void EntityList::CheckClientAggro(Client *around) {
        _ZP(EntityList_CheckClientAggro);
Index: zone/client.cpp
===================================================================
--- zone/client.cpp        (revision 1094)
+++ zone/client.cpp        (working copy)
@@ -268,6 +268,7 @@
        //for good measure:
        memset(&m_pp, 0, sizeof(m_pp));
        memset(&m_epp, 0, sizeof(m_epp));
+        memset(&m_suspended_minion, 0, sizeof(m_suspended_minion));
    PendingTranslocate = false;
        PendingSacrifice = false;
        BoatID = 0;
@@ -4767,6 +4768,72 @@
        return 0;
 }
 
+void Client::SuspendMinion(){
+        Client *c = this;
+       
+        Mob *pet =  c->GetPet();
+        NPC *npcPet = NULL;
+       
+        int cur_level=c->GetAA(aaID::aaSuspendedMinion);//SuspendedMinion ID
+
+        if(cur_level==0){
+                return;
+        }
+       
+        int spell_id=0;
+        if(pet==0){
+                if(m_suspended_minion.pet_id > 0){
+                        if(m_suspended_minion.pet_id){
+                                c->MakePet(m_suspended_minion.pet_id,spells[m_suspended_minion.pet_id].teleport_zone);
+                                pet = GetPet();
+                                npcPet = GetPet()->CastToNPC();
+                                if(cur_level >= 2){
+                                        npcPet->SetPetState(m_suspended_minion.pet_buffs, m_suspended_minion.pet_items);
+                                        pet->SendPetBuffsToClient();
+                                }
+                                npcPet->CalcBonuses();
+                                npcPet->SetHP(m_suspended_minion.pet_hp);
+                                npcPet->SetMana(m_suspended_minion.pet_mana);
+                                c->Message(clientMessageTell,"%s tells you, 'I live again...'",pet->GetCleanName());
+                                memset(&m_suspended_minion, 0, sizeof(m_suspended_minion));
+                        }else{
+                                c->Message(13,"Error: Couldn't find the spell id for your pet!");
+                                return;
+                        }
+                }else{
+                        return;
+                }
+        }else{
+                npcPet = GetPet()->CastToNPC();
+                spell_id=npcPet->GetPetSpellID();
+                if(spell_id){
+                        if(m_suspended_minion.pet_id > 0){
+                                c->Message(clientMessageError,"You cannot have more than one pet at a time.");
+                                return;
+                        }else if(pet->IsEngaged()){
+                                c->Message(clientMessageError,"Your pet must be a peace, first.");
+                                return;
+                        }else if(pet->HasAggro()){ //If the pet is on any aggro list
+                                c->Message(clientMessageBlue,"Your pet is the focus of something's attention.");
+                        }else{
+                               
+                                m_suspended_minion.pet_id = spell_id;
+                                m_suspended_minion.pet_hp = pet->GetHP();;
+                                m_suspended_minion.pet_mana = pet->GetMana();
+                                if(cur_level >= 2){
+                                        npcPet->GetPetState(m_suspended_minion.pet_buffs, m_suspended_minion.pet_items,m_suspended_minion.pet_name);
+                                }
+                               
+                                c->Message(clientMessageTell,"%s tells you, 'By your command, master.'",pet->GetCleanName());
+                                pet->Kill();
+                        }
+                }else{
+                        c->Message(13,"Error getting the spell_id from the npc_type id.");
+                        return;
+                }
+        }
+}
+
 void Client::SummonAndRezzAllCorpses()
 {
        pendingrezzexp = -1;
Index: zone/client.h
===================================================================
--- zone/client.h        (revision 1094)
+++ zone/client.h        (working copy)
@@ -150,6 +150,16 @@
        Client *MakeClient(EQStream* ieqs);
 };
 
+struct SuspendedMinion_Struct
+{
+        int16                                pet_id;
+        int16                                pet_hp;
+        int16                                pet_mana;
+        SpellBuff_Struct        pet_buffs[BUFF_COUNT];
+        int32                                pet_items[MAX_MATERIALS];
+        char                                pet_name[64];
+};
+
 class Client : public Mob
 {
 public:
@@ -894,6 +904,7 @@
        void CalcItemScale();
        bool CalcItemScale(int32 slot_x, int32 slot_y);
        void SummonAndRezzAllCorpses();
+        void SuspendMinion();
        void NotifyNewTitlesAvailable();
        void Signal(int32 data);
        Mob *GetBindSightTarget() { return bind_sight_target; }
@@ -1033,6 +1044,8 @@
        Inventory                                        m_inv;
        Object*                                                m_tradeskill_object;
 
+        SuspendedMinion_Struct                m_suspended_minion;
+
        AdventureInfo* m_offered_adventure;
        AdventureDetails *m_current_adventure;
 
Index: zone/command.cpp
===================================================================
--- zone/command.cpp        (revision 1094)
+++ zone/command.cpp        (working copy)
@@ -341,6 +341,7 @@
                command_add("guilds",NULL,0,command_guild) ||
                command_add("zonestatus","- Show connected zoneservers, synonymous with /servers",150,command_zonestatus) ||
                command_add("manaburn","- Use AA Wizard class skill manaburn on target",10,command_manaburn) ||
+                command_add("suspendminion","- Use pet class AA skill Suspend Minion",10,command_suspendminion) ||
                command_add("viewmessage","[id] - View messages in your tell queue",100,command_viewmessage) ||
                command_add("viewmessages",NULL,0,command_viewmessage) ||
                command_add("doanim","[animnum] [type] - Send an EmoteAnim for you or your target",50,command_doanim) ||
@@ -5158,6 +5159,11 @@
        }
 }
 
+void command_suspendminion(Client *c, const Seperator *sep)
+{
+        c->SuspendMinion();
+}
+
 void command_viewmessage(Client *c, const Seperator *sep)
 {
        char errbuf[MYSQL_ERRMSG_SIZE];
Index: zone/command.h
===================================================================
--- zone/command.h        (revision 1094)
+++ zone/command.h        (working copy)
@@ -218,6 +218,7 @@
 bool helper_guild_edit(Client *c, int32 dbid, int32 eqid, int8 rank, const char* what, const char* value);
 void command_zonestatus(Client *c, const Seperator *sep);
 void command_manaburn(Client *c, const Seperator *sep);
+void command_suspendminion(Client *c, const Seperator *sep);
 void command_viewmessage(Client *c, const Seperator *sep);
 void command_doanim(Client *c, const Seperator *sep);
 void command_randomfeatures(Client *c, const Seperator *sep);
Index: zone/mob.h
===================================================================
--- zone/mob.h        (revision 1094)
+++ zone/mob.h        (working copy)
@@ -841,6 +841,7 @@
        void CheckFlee();
 
        inline bool                        CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);}
+        bool                                HasAggro();
    float                                CalculateHeadingToTarget(float in_x, float in_y);
    bool                                CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
        bool                                CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);
Index: zone/pets.cpp
===================================================================
--- zone/pets.cpp        (revision 1094)
+++ zone/pets.cpp        (working copy)
@@ -213,8 +213,6 @@
        return base_hp;
 }
 */
-
-
 void Mob::MakePet(int16 spell_id, const char* pettype, const char *petname) {
        //see if we are a special type of pet (for command filtering)
        PetType type = petOther;
Index: zone/spell_effects.cpp
===================================================================
--- zone/spell_effects.cpp        (revision 1094)
+++ zone/spell_effects.cpp        (working copy)
@@ -2732,6 +2732,11 @@
                                        CastToClient()->GoToBind(4);
                                break;
                        }
+                        case SE_SuspendMinion:
+                        case SE_SuspendPet:
+                        {
+                                CastToClient()->SuspendMinion();
+                        }
 
                        case SE_ImprovedDamage:
                        case SE_ImprovedHeal:


demonstar55 01-16-2010 03:51 AM

I recommend using StringIDs, no idea if the messages are in zone/StringIDs.h though, they're simple to add though, just look them up in your EQ root folder in eqstr_us.txt, I think, might be the en one though, I always forget!

blmille2 01-16-2010 05:42 AM

I can't find any eqstr_us.txt. I found the stringids.h, but have yet to find the file the messages are actually stored in.

demonstar55 01-16-2010 06:02 AM

Quote:

Originally Posted by blmille2 (Post 182928)
I can't find any eqstr_us.txt. I found the stringids.h, but have yet to find the file the messages are actually stored in.

I said EQ root folder, as in where your game is installed

blmille2 01-16-2010 06:14 AM

Final Code with StringIDs
 
Code:

Code:

Index: zone/AA.h
===================================================================
--- zone/AA.h        (revision 1094)
+++ zone/AA.h        (working copy)
@@ -265,6 +265,7 @@
        aaParagonofSpirit = 291,                        //DB
        aaAdvancedInnateStrength = 292,                //works
        aaAdvancedInnateStamina = 302,                //works
+        //aaSuspendMinion = 308,                                //WIP -- brandon
        aaAdvancedInnateAgility = 312,                //works
        aaAdvancedInnateDexterity = 322,        //works
        aaAdvancedInnateIntelligence = 332, //works
Index: zone/aggro.cpp
===================================================================
--- zone/aggro.cpp        (revision 1094)
+++ zone/aggro.cpp        (working copy)
@@ -31,6 +31,20 @@
 extern Zone* zone;
 //#define LOSDEBUG 6
 
+bool Mob::HasAggro(){
+        bool hasAggro = false;
+       
+        list<NPC*> npc_list = entity_list.GetNPCList();
+        list<NPC*>::iterator iter;
+        iter = npc_list.begin();
+        while(iter != npc_list.end() && !hasAggro)
+        {
+                hasAggro |= (*iter)->CheckAggro(this);
+                iter++;
+        }
+        return hasAggro;
+}
+
 //look around a client for things which might aggro the client.
 void EntityList::CheckClientAggro(Client *around) {
        _ZP(EntityList_CheckClientAggro);
Index: zone/client.cpp
===================================================================
--- zone/client.cpp        (revision 1094)
+++ zone/client.cpp        (working copy)
@@ -268,6 +268,7 @@
        //for good measure:
        memset(&m_pp, 0, sizeof(m_pp));
        memset(&m_epp, 0, sizeof(m_epp));
+        memset(&m_suspended_minion, 0, sizeof(m_suspended_minion));
    PendingTranslocate = false;
        PendingSacrifice = false;
        BoatID = 0;
@@ -4767,6 +4768,74 @@
        return 0;
 }
 
+void Client::SuspendMinion(){
+        Client *c = this;
+       
+        Mob *pet =  c->GetPet();
+        NPC *npcPet = NULL;
+       
+        int cur_level=c->GetAA(aaID::aaSuspendedMinion);//SuspendedMinion ID
+
+        if(cur_level==0){
+                return;
+        }
+       
+        int spell_id=0;
+        if(pet==0){
+                if(m_suspended_minion.pet_id > 0){
+                        if(m_suspended_minion.pet_id){
+                                c->MakePet(m_suspended_minion.pet_id,spells[m_suspended_minion.pet_id].teleport_zone);
+                                pet = GetPet();
+                                npcPet = GetPet()->CastToNPC();
+                                if(cur_level >= 2){
+                                        npcPet->SetPetState(m_suspended_minion.pet_buffs, m_suspended_minion.pet_items);
+                                        pet->SendPetBuffsToClient();
+                                }
+                                npcPet->CalcBonuses();
+                                npcPet->SetHP(m_suspended_minion.pet_hp);
+                                npcPet->SetMana(m_suspended_minion.pet_mana);
+
+                                //c->Message(clientMessageTell,"%s tells you, 'I live again...'",pet->GetCleanName());
+                                c->Message_StringID(clientMessageTell,SUSPEND_MINION_UNSUSPEND,pet->GetCleanName());
+                               
+                                memset(&m_suspended_minion, 0, sizeof(m_suspended_minion));
+                        }else{
+                                c->Message(13,"Error: Couldn't find the spell id for your pet!");
+                                return;
+                        }
+                }else{
+                        return;
+                }
+        }else{
+                npcPet = GetPet()->CastToNPC();
+                spell_id=npcPet->GetPetSpellID();
+                if(spell_id){
+                        if(m_suspended_minion.pet_id > 0){
+                                c->Message_StringID(clientMessageError,ONLY_ONE_PET);
+                                return;
+                        }else if(pet->IsEngaged()){
+                                c->Message_StringID(clientMessageError,SUSPEND_MINION_FIGHTING);
+                                return;
+                        }else if(pet->HasAggro()){ //If the pet is on any aggro list
+                                c->Message_StringID(clientMessageBlue,SUSPEND_MINION_HAS_AGGRO);
+                        }else{
+                               
+                                m_suspended_minion.pet_id = spell_id;
+                                m_suspended_minion.pet_hp = pet->GetHP();;
+                                m_suspended_minion.pet_mana = pet->GetMana();
+                                if(cur_level >= 2){
+                                        npcPet->GetPetState(m_suspended_minion.pet_buffs, m_suspended_minion.pet_items,m_suspended_minion.pet_name);
+                                }
+                                c->Message_StringID(clientMessageTell,SUSPEND_MINION_SUSPEND,pet->GetCleanName());
+                                pet->Kill();
+                        }
+                }else{
+                        c->Message(13,"Error getting the spell_id from the npc_type id.");
+                        return;
+                }
+        }
+}
+
 void Client::SummonAndRezzAllCorpses()
 {
        pendingrezzexp = -1;
Index: zone/client.h
===================================================================
--- zone/client.h        (revision 1094)
+++ zone/client.h        (working copy)
@@ -150,6 +150,16 @@
        Client *MakeClient(EQStream* ieqs);
 };
 
+struct SuspendedMinion_Struct
+{
+        int16                                pet_id;
+        int16                                pet_hp;
+        int16                                pet_mana;
+        SpellBuff_Struct        pet_buffs[BUFF_COUNT];
+        int32                                pet_items[MAX_MATERIALS];
+        char                                pet_name[64];
+};
+
 class Client : public Mob
 {
 public:
@@ -894,6 +904,7 @@
        void CalcItemScale();
        bool CalcItemScale(int32 slot_x, int32 slot_y);
        void SummonAndRezzAllCorpses();
+        void SuspendMinion();
        void NotifyNewTitlesAvailable();
        void Signal(int32 data);
        Mob *GetBindSightTarget() { return bind_sight_target; }
@@ -1033,6 +1044,8 @@
        Inventory                                        m_inv;
        Object*                                                m_tradeskill_object;
 
+        SuspendedMinion_Struct                m_suspended_minion;
+
        AdventureInfo* m_offered_adventure;
        AdventureDetails *m_current_adventure;
 
Index: zone/command.cpp
===================================================================
--- zone/command.cpp        (revision 1094)
+++ zone/command.cpp        (working copy)
@@ -341,6 +341,7 @@
                command_add("guilds",NULL,0,command_guild) ||
                command_add("zonestatus","- Show connected zoneservers, synonymous with /servers",150,command_zonestatus) ||
                command_add("manaburn","- Use AA Wizard class skill manaburn on target",10,command_manaburn) ||
+                command_add("suspendminion","- Use pet class AA skill Suspend Minion",10,command_suspendminion) ||
                command_add("viewmessage","[id] - View messages in your tell queue",100,command_viewmessage) ||
                command_add("viewmessages",NULL,0,command_viewmessage) ||
                command_add("doanim","[animnum] [type] - Send an EmoteAnim for you or your target",50,command_doanim) ||
@@ -5158,6 +5159,11 @@
        }
 }
 
+void command_suspendminion(Client *c, const Seperator *sep)
+{
+        c->SuspendMinion();
+}
+
 void command_viewmessage(Client *c, const Seperator *sep)
 {
        char errbuf[MYSQL_ERRMSG_SIZE];
Index: zone/command.h
===================================================================
--- zone/command.h        (revision 1094)
+++ zone/command.h        (working copy)
@@ -218,6 +218,7 @@
 bool helper_guild_edit(Client *c, int32 dbid, int32 eqid, int8 rank, const char* what, const char* value);
 void command_zonestatus(Client *c, const Seperator *sep);
 void command_manaburn(Client *c, const Seperator *sep);
+void command_suspendminion(Client *c, const Seperator *sep);
 void command_viewmessage(Client *c, const Seperator *sep);
 void command_doanim(Client *c, const Seperator *sep);
 void command_randomfeatures(Client *c, const Seperator *sep);
Index: zone/mob.h
===================================================================
--- zone/mob.h        (revision 1094)
+++ zone/mob.h        (working copy)
@@ -841,6 +841,7 @@
        void CheckFlee();
 
        inline bool                        CheckAggro(Mob* other) {return hate_list.IsOnHateList(other);}
+        bool                                HasAggro();
    float                                CalculateHeadingToTarget(float in_x, float in_y);
    bool                                CalculateNewPosition(float x, float y, float z, float speed, bool checkZ = false);
        bool                                CalculateNewPosition2(float x, float y, float z, float speed, bool checkZ = true);
Index: zone/pets.cpp
===================================================================
--- zone/pets.cpp        (revision 1094)
+++ zone/pets.cpp        (working copy)
@@ -213,8 +213,6 @@
        return base_hp;
 }
 */
-
-
 void Mob::MakePet(int16 spell_id, const char* pettype, const char *petname) {
        //see if we are a special type of pet (for command filtering)
        PetType type = petOther;
Index: zone/spell_effects.cpp
===================================================================
--- zone/spell_effects.cpp        (revision 1094)
+++ zone/spell_effects.cpp        (working copy)
@@ -2732,6 +2732,11 @@
                                        CastToClient()->GoToBind(4);
                                break;
                        }
+                        case SE_SuspendMinion:
+                        case SE_SuspendPet:
+                        {
+                                CastToClient()->SuspendMinion();
+                        }
 
                        case SE_ImprovedDamage:
                        case SE_ImprovedHeal:
Index: zone/StringIDs.h
===================================================================
--- zone/StringIDs.h        (revision 1094)
+++ zone/StringIDs.h        (working copy)
@@ -66,6 +66,7 @@
 #define ONLY_ONE_PET                                246                //You cannot have more than one pet at a time.
 #define CANNOT_CHARM_YET                        248                //Your target is too high of a level for your charm spell.
 #define NO_PET                                                255                //You do not have a pet.
+#define SUSPEND_MINION_HAS_AGGRO        256                //Your pet is the focus of something's attention.
 #define CORPSE_CANT_SENSE                        262                //You cannot sense any corpses for this PC in this zone.
 #define SPELL_NO_HOLD                                263                //Your spell did not take hold.
 #define CANNOT_CHARM                                267                //This NPC cannot be charmed.
@@ -184,6 +185,9 @@
 #define DOORS_SUCCESSFUL_PICK                1457        //You successfully picked the lock.
 #define PLAYER_CHARMED                                1461        //You lose control of yourself!
 #define TRADER_BUSY                                        1468        //That Trader is currently with a customer. Please wait until their transaction is finished.
+#define SUSPEND_MINION_UNSUSPEND        3267        //%1 tells you, 'I live again...'
+#define SUSPEND_MINION_SUSPEND                3268        //%1 tells you, 'By your command, master.'
+#define SUSPEND_MINION_FIGHTING                3270    //Your pet must be at peace, first.
 #define WHOALL_NO_RESULTS                        5029        //There are no players in EverQuest that match those who filters.
 #define PETITION_NO_DELETE                        5053        //You do not have a petition in the queue.
 #define PETITION_DELETED                        5054        //Your petition was successfully deleted.


steve 01-16-2010 12:16 PM

Awesome. :)

Think you could do the next step?

Quote:

Persistent Minion: This ability upgrades your Suspended Minion ability to allow pets to remain suspended across zone lines. Also, if you camp with a suspended pet and have this ability, the pet will be available to you when you return.
Live also just recently implemented a change so that you can camp without suspending a pet and it will be there when you get back, without even needing the AA.

blmille2 01-16-2010 12:40 PM

Persistent Minion requires that we store the minion information to the database somewhere in the player profile. There are already some devs working on where that should go in the near future.

I forgot that there are servers that have a max level above PEQ, so I can see where this would benefit players on those servers.

But, the good news is it looks like it should be pretty simple to extend once there is some free room in the profile for the suspended minion data.

blmille2 01-18-2010 02:36 PM

Bump.

Are we going to check in this code?

Thanks!

Derision 01-18-2010 03:31 PM

I'll get to it, probably at the weekend when I have more time to test it, unless another Dev has time to do it before then.

KLS 01-18-2010 04:38 PM

Code:

//WIP -- brandon
I know you see names in comments all over the code but please don't add any more. They don't really add anything and are basically graffiti inside the code.

I'm taking them out where I can find them, and if I ever get around to posting code standards no names will be in there.

Other than that I think it's to the acceptable point now.

Derision 01-19-2010 02:00 PM

I've committed this in Rev1123.

I put the SuspendedMinion struct into the Player Profile, and also implemented Persistent Minion as it was a simple two line addition to do so.

There was an existing method, EntityList::Fighting which appeared to have the same functionality as your HasAggro method, so I used this.

Most of the other changes I made were purely cosmetic.

I tested it using a Necro ... let me know if I broke anything in the process of committing it.

Finally, nice work, thanks for the contribution, I'm sure the classes who can use this AA will appreciate it.


All times are GMT -4. The time now is 07:48 PM.

Powered by vBulletin®, Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.