EQEmulator Forums

EQEmulator Forums (https://www.eqemulator.org/forums/index.php)
-   Development::Development (https://www.eqemulator.org/forums/forumdisplay.php?f=590)
-   -   Feign Death Reliability Fix - Pet Fix - Feign Memory Overhaul (https://www.eqemulator.org/forums/showthread.php?t=20826)

fathernitwit 06-23-2006 01:46 PM

hey,

diffs look good.

A few comments on the code:
- where you do if(!owner->CastToClient()->GetFeigned()){, you need to be sure that owner is a client first, use if(owner->IsClient() && !owner->Cast....
- make the 120000 value part of the timer duration enum in features.h
- you should check feigned before you call scanarea_timer.Check... so put the check between 'ret and 'scanarea_timer.Check()', also call GetFeigned instead of using `feigned` directly.
- Please do not use the LinkedList data structure, we are doing everything we can to get rid of that, use the STL vector or list.. further, never store string pointers in a data structure like that unless you can garuntee the existence of that pointer until the list is cleared (which you cannot in this case). Use a STL string object in the future... BUT you should not be storing the character's name in the list anyhow, its use their ->CharacterID() and then use GetClientByCharID
- Do not use rand()/RAND_MAX, use MakeRandomInt/Float.
- Do not use CastToMob() unless you truely have a pointer to an Entity object (basically nowhere)... everything else is already derived from a Mob, and does not require a cast.
- Your use of CastToNPC() in ClearFeignAggro is unnescecary, your iterator is already an NPC *... casting is bad, avoid at all costs.
- In ClearFeignAggro, you need to either check to see if the object is a Client object before calling CastToClient for AddFeignMemory, or you need to make ClearFeignAggro take a Client *, and have its caller check it.
- please remove depricated functions, in particular SetFeignMemory and the feign_memory member variable)
- Please only send emotes/messages to the client when they match what live sends, if you add other things for debugging, please use the _log facility instead (use #logs to get messages in game)

unicorn97211 06-23-2006 02:56 PM

I'll work on these changes over the weekend and see how far I can get. Using the STL stuff will be something new to learn but the rest of it seems straightforward. Thanks for the feedback on my rusty c skills :)

Will post a new diff when I have another draft ready.

unicorn97211 06-25-2006 05:55 PM

Latest Diff
 
Here is the latest diffs after making the recommended changes.

Code:

--- C:\Code\EQEmu800\zone\attack.cpp        Wed Jun 07 18:29:26 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\attack.cpp        Sun Jun 25 22:25:28 2006
@@ -1727,10 +1727,18 @@
       
        if (other == myowner)
                return;
-        if (owner) { // Other has a pet, add him and it
+        if (owner) { // Other is a pet, add him and it
                hate_list.Add(other, hate, 0, bFrenzy, !iBuffTic);
+                // EverHood 6/12/06
+                // Can't add a feigned owner to hate list
+                if(owner->IsClient()){
+                        if(!owner->CastToClient()->GetFeigned()){
                hate_list.Add(owner, 1, damage, false, !iBuffTic);
        }
+                }else{
+                        hate_list.Add(owner, 1, damage, false, !iBuffTic);
+                }
+        }
        else { // Other has no pet, add other
                hate_list.Add(other, hate, damage, false, !iBuffTic);
        }
@@ -2068,9 +2077,21 @@
                else
                        hate = damage; // normal aggro for everything else
               
-                mlog(COMBAT__HITS, "Generating hate %d towards %s", hate, attacker->GetName());
-                // now add done damage to the hate list
+                // EverHood 6/12/06
+                if(attacker->IsClient()){
+                        // check if attacker is feigned
+                        if(attacker->CastToClient()->GetFeigned()){
+                                hate = -1; // no hate for feigned attackers
+                        }
+                }
+               
+                if(hate != -1){
+                        // attacker generated some hate so
+                        // add damage done by attacker to the hate list
+                        // mlog(COMBAT__HITS, "Generating %d hate towards %s", hate, attacker->GetName());
                AddToHateList(attacker, hate, damage, true, false, iBuffTic);
+                }
+
        }
   
        if(damage > 0) {
--- C:\Code\EQEmu800\zone\client.cpp        Fri May 12 19:35:58 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\client.cpp        Sun Jun 25 17:55:21 2006
@@ -143,6 +143,8 @@
        ooc_timer(1000),
        shield_timer(500),
        fishing_timer(8000),
+        // EverHood 6/16/06
+        forget_timer(0),
 #ifdef REVERSE_AGGRO
        scanarea_timer(AIClientScanarea_delay),
 #endif
@@ -1763,13 +1765,25 @@
 }
 
 void Client::SetFeigned(bool in_feigned) {
+        feigned=in_feigned;
        if (in_feigned)
        {
+// EverHood 6/12/06
+// Live doesn't kill pets when owner feigns anymore
+// Hasn't since mobs quit agroing pets.
+// If you're worried necros will Feign and let pet solo
+// mobs turn this on in Features.h.
+// *Note: If a necro pet can solo an xp bearing mob while owner is FD
+//                  that mob needs it's stats bumped.
+#ifdef KILL_PET_ON_FEIGN
                SetPet(0);
+#endif
                SetHorseId(0);
                entity_list.ClearFeignAggro(this);
+                forget_timer.Start(FeignMemoryDuration);
+        }else{
+                forget_timer.Disable();
        }
-        feigned=in_feigned;
  }
 
 void Client::LogMerchant(Client* player, Mob* merchant, Merchant_Sell_Struct* mp, const Item_Struct* item, bool buying)
--- C:\Code\EQEmu800\zone\client.h        Wed Jun 07 18:29:26 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\client.h        Sun Jun 25 22:29:31 2006
@@ -512,7 +512,9 @@
        inline void        SetBecomeNPCLevel(int8 level) { npclevel = level; }
        bool        LootToStack(uint32 itemid);
        void        SetFeigned(bool in_feigned);
-        inline bool    GetFeigned()        { return(GetAppearance() != eaDead ? false : feigned); }
+        // EverHood 6/16/06
+        /// this cures timing issues cuz dead animation isn't done but server side feigning is?
+        inline bool    GetFeigned()        {return(feigned); }
        EQStreamInterface* Connection() { return eqs; }
 #ifdef PACKET_PROFILER
        void DumpPacketProfile() { if(eqs) eqs->DumpPacketProfile(); }
@@ -768,6 +770,9 @@
        Timer        ooc_timer;
        Timer        shield_timer;
        Timer        fishing_timer;
+        // EverHood 6/16/06
+        // our 2 min everybody forgets you timer
+        Timer        forget_timer;
 #ifdef REVERSE_AGGRO
        Timer        scanarea_timer;
 #endif
--- C:\Code\EQEmu800\zone\client_process.cpp        Mon Apr 17 06:59:14 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\client_process.cpp        Sun Jun 25 01:29:00 2006
@@ -533,7 +533,8 @@
 #ifdef REVERSE_AGGRO
        //At this point, we are still connected, everything important has taken
        //place, now check to see if anybody wants to aggro us.
-        if(ret && scanarea_timer.Check()) {
+        // Everhood 6/15/06 - only if client is not feigned
+        if(ret && !GetFeigned() && scanarea_timer.Check()) {
                entity_list.CheckClientAggro(this);
        }
 #endif       
@@ -576,7 +577,12 @@
                }
                OnDisconnect(true);
        }
-       
+        // EverHood Feign Death 2 minutes and zone forgets you
+        if (forget_timer.Check()) {
+                forget_timer.Disable();
+                entity_list.ClearZoneFeignAggro(this);
+                Message(0,"Your enemies have forgotten you!");
+        }
       
        return ret;
 }
--- C:\Code\EQEmu800\zone\entity.cpp        Wed May 31 21:13:32 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\entity.cpp        Sun Jun 25 21:28:04 2006
@@ -2471,12 +2471,31 @@
        iterator.Reset();
        while(iterator.MoreElements())
        {
-                if (iterator.GetData()->CastToNPC()->CheckAggro(targ))
+                if (iterator.GetData()->CheckAggro(targ))
                {
-                        iterator.GetData()->CastToNPC()->RemoveFromHateList(targ);
-                        if (iterator.GetData()->CastToMob()->GetLevel() >= 35)
-                                iterator.GetData()->CastToNPC()->SetFeignMemory(targ->CastToMob()->GetName());
+                        iterator.GetData()->RemoveFromHateList(targ);
+                        // EverHood 6/24/06
+                        // For client targets if the mob that hated us is 35+
+                        // there is a 3 outta 5 chance he adds us to feign memory
+                        if(targ->IsClient()){
+                                if (iterator.GetData()->GetLevel() >= 35){
+                                        if(MakeRandomInt(1,100)<=60){
+                                                iterator.GetData()->AddFeignMemory(targ->CastToClient());
                }
+                                }
+                        }
+                }
+                iterator.Advance();
+        }
+}
+// EverHood 6/17/06
+void EntityList::ClearZoneFeignAggro(Client* targ)
+{
+        LinkedListIterator<NPC*> iterator(npc_list);
+        iterator.Reset();
+        while(iterator.MoreElements())
+        {
+                iterator.GetData()->RemoveFromFeignMemory(targ);
                iterator.Advance();
        }
 }
--- C:\Code\EQEmu800\zone\entity.h        Wed May 31 21:13:32 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\entity.h        Sun Jun 18 02:07:29 2006
@@ -251,6 +251,8 @@
 
    void    Process();
        void        ClearFeignAggro(Mob* targ);
+        // Everhood 6/17/06
+        void        ClearZoneFeignAggro(Client* targ);
       
        bool        Fighting(Mob* targ);
        void    RemoveFromHateLists(Mob* mob, bool settoone = false);
--- C:\Code\EQEmu800\zone\features.h        Sat Mar 18 21:09:26 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\features.h        Sun Jun 25 22:35:20 2006
@@ -207,7 +207,8 @@
        AIassistcheck_delay = 3000,                //now often a fighting NPC will yell for help
        ClientProximity_interval = 1000,
        Tribute_duration = 600000,
-        ZoneTimerResolution = 3                        //sleep time between zone main loop runs (milliseconds)
+        ZoneTimerResolution = 3,                        //sleep time between zone main loop runs (milliseconds)
+        FeignMemoryDuration = 120000 // EverHood - Duration player must feign death to clear zonewide agro.
 };
 
 enum {        //some random constants
@@ -262,7 +263,7 @@
 #define MIN_FACTION -1500
 
 //The Level Cap:
-#define LEVEL_CAP 65                //hard cap is 127
+#define LEVEL_CAP 70        //hard cap is 127
 
 //the square of the maximum range at whihc you could possibly use NPC services (shop, tribute, etc)
 #define USE_NPC_RANGE2 200*200                //arbitrary right now
--- C:\Code\EQEmu800\zone\MobAI.cpp        Wed May 31 21:13:32 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\MobAI.cpp        Sun Jun 25 21:55:28 2006
@@ -938,16 +938,30 @@
                                if (cur_wp_x == GetX() && cur_wp_y == GetY())
                                {        // are we there yet? then stop
                                        mlog(AI__WAYPOINTS, "We have reached waypoint %d (%.3f,%.3f,%.3f) on grid %d", cur_wp, GetX(), GetY(), GetZ(), GetGrid());
                                        SetWaypointPause();
                                        SetAppearance(eaStanding, false);
                                        SetMoving(false);
                                        SendPosition();
+                                        // EverHood - wipe feign memory since we reached our first waypoint
+                                        if(cur_wp==1){
+                                                ClearFeignMemory();
+                                        }
                                }
@@ -969,6 +983,8 @@
      {
                if(moved) {
                        mlog(AI__WAYPOINTS, "Reached guard point (%.3f,%.3f,%.3f)", guard_x, guard_y, guard_z);
+                        // EverHood 6/18/06
+                        ClearFeignMemory();
                        moved=false;
                        SetMoving(false);
                        SendPosition();


unicorn97211 06-25-2006 05:56 PM

Diffs (Cont)
 
Code:

--- C:\Code\EQEmu800\zone\npc.cpp        Wed May 31 21:13:32 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\npc.cpp        Sun Jun 25 01:29:00 2006
@@ -233,8 +233,6 @@
        pet_spell_id = 0;
       
        delaytimer = false;
-    feign_memory = "0";
-        forgetchance = 0;
        attack_event = false;
        attack_speed = d->attack_speed;
 
@@ -481,30 +479,19 @@
    if (IsStunned()||IsMezzed())
            return true;
 
-        //Feign Death Memory
-        if (forget_timer.Check() && strstr(GetFeignMemory(),"0") == NULL) {
-                Client* remember_client = entity_list.GetClientByName(GetFeignMemory());
-                if (remember_client != 0)
+        // EverHood - 6/14/06
+        // Improved Feign Death Memory
+        if (forget_timer.Check() && !feign_memory_list.empty()) {
+                std::list<int32>::iterator RememberedCharID;
+                for (RememberedCharID=feign_memory_list.begin(); RememberedCharID != feign_memory_list.end(); RememberedCharID++)
+                {
+                        Client* remember_client = entity_list.GetClientByCharID(*RememberedCharID);
+                        if (!remember_client->GetFeigned())
                {
-                        if (!remember_client->CastToClient()->GetFeigned())
-                        {
-                                AddToHateList(remember_client,1);
-                                SetFeignMemory("0");
-                                forgetchance = 0;
-                        }
-                        else if (rand()%100 <= forgetchance)
-                        {
-                                SetFeignMemory("0");
-                                forgetchance = 0;
-                        }
-                        else
-                        {
-                                forgetchance += 1;
-                        }
+                                AddToHateList(remember_client->CastToMob(),1);
+                                feign_memory_list.remove(*RememberedCharID);
+                                break;
                }
-                else
-                {
-                        SetFeignMemory("0");
                }
        }
       
@@ -519,6 +506,22 @@
    return true;
 }
 
+        // EverHood 6/14/06 - FD memory
+        void  NPC::AddFeignMemory(Client* attacker) {
+                feign_memory_list.push_back(attacker->CharacterID());
+        }
+        void  NPC::RemoveFromFeignMemory(Client* attacker){
+                if(!feign_memory_list.empty()){
+                        int32 attacker_charid = attacker->CharacterID();
+                        feign_memory_list.remove(attacker_charid);
+                }
+        }
+        void  NPC::ClearFeignMemory(){
+                if(!feign_memory_list.empty()){
+                        feign_memory_list.clear();
+                }
+        }
+
 int32 NPC::CountLoot() {
        return(itemlist.size());
 }
--- C:\Code\EQEmu800\zone\npc.h        Sun Mar 19 20:04:48 2006
+++ C:\EQEmuSP\Source\0.7.0\zone\npc.h        Sun Jun 25 01:29:00 2006
@@ -161,9 +161,11 @@
    bool    IsOnHatelist(Mob*p) { return hate_list.IsOnHateList(p);}
 
        void        SetNPCFactionID(sint32 in) { npc_faction_id = in; database.GetFactionIdsForNPC(npc_faction_id, &faction_list, &primary_faction); }
-        void        SetFeignMemory(const char* num) {feign_memory = num;}
-
-        inline const char*    GetFeignMemory()        { return feign_memory; }
+        // EverHood 6/14/06
+        // Mobs need to be able to remember more than one feigned attacker
+        void        AddFeignMemory(Client* attacker);
+        void        RemoveFromFeignMemory(Client* attacker);
+        void        ClearFeignMemory();
 
        float  org_x, org_y, org_z, org_heading;
       
@@ -251,8 +253,8 @@
       
        int16        max_dmg;
        int16        min_dmg;
-        const char*        feign_memory;
-        int8    forgetchance;
+        // EverHood 6/14/06
+        std::list<int32> feign_memory_list;
       
        //pet crap:
        int16        pet_spell_id;


fathernitwit 06-28-2006 01:31 PM

ok,

Looks good. I got this in, untested, so grab the next build with it mentioned in the changelog and test it for me.

I made a few changes.
- I fixed an iterator delete bug, you cannot remove an element from any STL container and expect the iterator which pointed to that element to stay valid. Each container has its own erase-while-iterating rules and trick.
- I also changed it from a list to a set, just to ensure uniqueness.
- I moved everything up into Mob so in theory charmed players would exhibit the same behavior. (plus it made the next comment easier)
- Its bad form to name two timers the same thing when they have different purposes, it confused me for a while. Your NPC forget check timer was also somewhat unnescesary (as well as being in a bad spot, that code gets called very rapidly, and your slower timer should be burried inside other shorter timers so it dosent get checked so often.) Because of this, I just eliminated it, and moved the "look for people who got up" code into the AI scan area timer (where we look for people to aggro, which had the same duration).

unicorn97211 06-28-2006 04:28 PM

Great! I look forward to seeing how you implemented the above mentioned changes. The more I learn about the structure and where things should go and what the best objects to use in which situations, the more effective I can fix and or add features. For the immediate future I plan to focus on fixes to the necro class since it's a class I know thoroughly. I hope that more people with class specific knowledge can do the same to free the core devs up for the important things like getting AA's working in 7.0 :)

unicorn97211 06-30-2006 08:40 AM

I grabbed v.812 and did some testing. I found that I am not being remembered. I popped in a debug to tell me when I was being added to the feign memory list and that seems to be working fine. However when I stand up the mob does not remember me and add me to his hate list. It looks as though the memory check isn't being executed. It also looks to me as if the memory check won't occur if the mob is engaged. I'm thinking the mob should remember you even if it's fighting with someone else and you get up.

i.e. If I pull a mob to my group and feign. While the group is fighting the mob , I stand up. My groupies wipe. I should have been remembered when I stood up while the mob was engaged so that when my groupies wipe I am on the hate list even though I may be out of aggro range.

I'm not sure about this as I haven't had time to think through all the possible situations.

FNW: do you want me to try and debug whats going wrong with the memory check the way you implemented it or do you have time to debug it?

fathernitwit 06-30-2006 04:51 PM

what you describe is ultimately what should happen, as soon as the mob is no longer engaged (500ms later prolly), it will look for people to remember, but not until it is no longer engaged (no point in checking while engaged since we come back with only 1 hate).

feel free to debug it.

unicorn97211 07-01-2006 02:31 PM

Just got back into town, that makes sense. I'll toss in some debug messages and such and see if I can track down why they aren't remembering me when I get up even though I've been added to feign memory.

unicorn97211 07-01-2006 08:53 PM

Found the culprit...
 
This is causing fd memory to never be checked.

Code:

#ifdef REVERSE_AGGRO
        if(IsNPC() && !CastToNPC()->WillAggroNPCs())
                AIscanarea_timer->Disable();
#endif

FNW: Where do you recommend moving the feign memory check to?

fathernitwit 07-04-2006 03:23 AM

ah crap, forgot about reverse aggro.

I moved it to its own AI timer, give it a try next rev.

unicorn97211 07-06-2006 10:02 AM

Works like a charm in 0.7.0-815 :)

I need to play more to know for sure but it feels like they don't remember you often enough so perhaps we should make the chance to remember a user defined percentage.


All times are GMT -4. The time now is 06:08 PM.

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