Feign Reliability Fix
Feign was failing outside our control.
client_process.cpp
In Client::Process
Change
	Code:
	#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()) {
		entity_list.CheckClientAggro(this);
	}
#endif
 to
	Code:
	#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 check prox agro if we are not feigned
		if(!feigned){
			entity_list.CheckClientAggro(this);
		}
	}
#endif
 client.h
Change
	
	Code:
	inline bool    GetFeigned()	{ return(GetAppearance() != eaDead ? false : feigned); }
 To
	Code:
		// EverHood 6/16/06
	// this cures timing issues cuz dead animation isn't done but server side feigning is?
	inline bool    GetFeigned()	{return feigned; }
 Feigned Owner Pet Aggro Fix
Now that pets don't die when we feign, this stops us from inheriting any hate the pet does while we are fiegned.
i.e. If someone trains my pet with 20 mobs and I feign, when my pet dies the mobs should return home. Pre-Fix when my pet died the mobs would begin attacking me even though I am feigned.
attack.cpp
In Mob::AddToHateList
Change
	Code:
		if (owner) { // Other has a pet, add him and it
		hate_list.Add(other, hate, 0, bFrenzy, !iBuffTic);
		hate_list.Add(owner, 1, damage, false, !iBuffTic);
	}
 To
	Code:
		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->CastToClient()->GetFeigned()){
			hate_list.Add(owner, 1, damage, false, !iBuffTic);
		}
	}
 Improved Feign Memory
The current feign memory only allows an NPC to remember a single attacker and the attacker was being remembered 100% of the time. When the NPCs feign memory was being processed, the dice were thrown and the attacker got a chance to be forgotten and if he lost the roll enough times the attacker was eventually removed from feign memory. This was a problem since Necro A could aggro then feign then Necro B could aggro and feign overwriting Necro A in the feign memory allowing Necro A to get up when he shouldn't be able to yet. This did not follow live feign memory functionality in any way.
I've replaced the single slot feign memory with a feign memory list to hold multiple attackers. I've changed the code so that when you feign, if the NPC is level 35+, the dice are thrown and there is a 3 in 5 chance you will be added to the NPCs feign memory list. When the NPC processes its feign memory, any attacker on it that has stood up will be added back to that NPCs hate list. If the NPC reaches it's guard point (spawn point) it will clear all attackers from it's feign memory. If the NPC is on a grid and reaches waypoint 1 it will clear all attackers from it's feign memory.
npc.h
Change
	Code:
		void	SetFeignMemory(const char* num) {feign_memory = num;}
	inline const char*    GetFeignMemory()	{ return feign_memory; }
 To
	Code:
		// 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();
 Change
	Code:
		const char*	feign_memory;
 To
	Code:
		// EverHood 6/14/06
	LinkedList<const char*> feign_memory_list;
 npc.cpp
In NPC::Process
Change
	Code:
		//Feign Death Memory
	if (forget_timer.Check() && strstr(GetFeignMemory(),"0") == NULL) {
		Client* remember_client = entity_list.GetClientByName(GetFeignMemory());
		if (remember_client != 0)
		{
			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;
			}
		}
		else
		{
			SetFeignMemory("0");
		}
	}
 To
	Code:
		// EverHood - 6/14/06
	// Improved Feign Death Memory
	if (forget_timer.Check()) {
		LinkedListIterator<const char*> iterator(feign_memory_list);
		iterator.Reset();
		while(iterator.MoreElements())
		{
			Client* remember_client = entity_list.GetClientByName(iterator.GetData());
			if (!remember_client->CastToClient()->GetFeigned())
			{
				AddToHateList(remember_client,1);
				iterator.RemoveCurrent();
				// Personal humor
				Emote("realizes %s wasn't really dead",remember_client->GetName());
			}
			iterator.Advance();
		}		
	}
 Add
	Code:
		// EverHood 6/14/06 - Feign Death memory 
	void   NPC::AddFeignMemory(Client* attacker) {
		feign_memory_list.Insert(attacker->CastToMob()->GetName());
		// Leaving this debug in is kinda interesting...
		Emote("is suspicious of %ss unexpected death.",attacker->GetName());
	}
	void   NPC::RemoveFromFeignMemory(Client* attacker){
		LinkedListIterator<const char*> iterator(feign_memory_list);
		iterator.Reset();
		while(iterator.MoreElements())
		{
			if(iterator.GetData() == attacker->GetName()){
				// Leaving this debug in is kinda interesting...
				this->CastToMob()->Emote("loses interest in %s.",attacker->GetName());
				iterator.RemoveCurrent();
			}
			iterator.Advance();
		}
	}
	void   NPC::ClearFeignMemory(){
		if(feign_memory_list.Count()>0){
			feign_memory_list.Clear();
			// Leaving this debug in is kinda interesting...
			this->CastToMob()->Emote("is no longer suspicious of the dead.");
		}
	}
 entity.cpp
Change
	Code:
	void EntityList::ClearFeignAggro(Mob* targ)
{
	LinkedListIterator<NPC*> iterator(npc_list);
	iterator.Reset();
	while(iterator.MoreElements())
	{
		if (iterator.GetData()->CastToNPC()->CheckAggro(targ))
		{
			iterator.GetData()->CastToNPC()->RemoveFromHateList(targ);
			if (iterator.GetData()->CastToMob()->GetLevel() >= 35)
				iterator.GetData()->CastToNPC()->SetFeignMemory(targ->CastToMob()->GetName());
		}
		iterator.Advance();
	}
}
 To
	Code:
	void EntityList::ClearFeignAggro(Mob* targ)
{
	LinkedListIterator<NPC*> iterator(npc_list);
	iterator.Reset();
	while(iterator.MoreElements())
	{
		if (iterator.GetData()->CastToNPC()->CheckAggro(targ))
		{
			iterator.GetData()->CastToNPC()->RemoveFromHateList(targ);
			if (iterator.GetData()->CastToMob()->GetLevel() >= 35)
				// EverHood 6/14/06
				// the mob that hated us is 35+ so 3 outta 5 chance 
				// he adds us to its feign memory. 
				if(((float)rand()/RAND_MAX)*100 < 40){
					iterator.GetData()->CastToNPC()->AddFeignMemory(targ->CastToClient());
				}
		}
		iterator.Advance();
	}
}
 MobAI.cpp
In NPC::AI_DoMovement
Change
	Code:
					{	// 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();
				}
 To
	Code:
					{	// 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();
					}
				}
 Change
	Code:
				mlog(AI__WAYPOINTS, "Reached guard point (%.3f,%.3f,%.3f)", guard_x, guard_y, guard_z);
			moved=false;
 To
	Code:
				mlog(AI__WAYPOINTS, "Reached guard point (%.3f,%.3f,%.3f)", guard_x, guard_y, guard_z);
			// EverHood 6/18/06- we are home so clear our feign memory
			ClearFeignMemory();
			moved=false;
 Feign Memory 2 Minute Wipe
I saw no code to handle this. When a client is feigned for 2 minutes, clear client off all feign memory lists in zone and let client know it is clear to stand up.
Client.h
Change
	Code:
		Timer	fishing_timer;
#ifdef REVERSE_AGGRO
	Timer	scanarea_timer;
#endif
 To
	Code:
		Timer	fishing_timer;
	// EverHood 6/16/06
	// our 2 min everybody forgets you timer
	Timer	forget_timer;
#ifdef REVERSE_AGGRO
	Timer	scanarea_timer;
#endif
 client.cpp
In Client::Client
Change
	Code:
		fishing_timer(8000),
#ifdef REVERSE_AGGRO
	scanarea_timer(AIClientScanarea_delay),
#endif
 To
	Code:
		fishing_timer(8000),
	// EverHood 6/16/06
	forget_timer(120000),
#ifdef REVERSE_AGGRO
	scanarea_timer(AIClientScanarea_delay),
#endif
 client_process.cpp
In Client::Process
Change
	Code:
			OnDisconnect(true);
	}
	
	
	return ret;
}
 To
	Code:
			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 your aggressions.");
	}
	
	return ret;
}
 entity.h
Change
	Code:
		void	ClearFeignAggro(Mob* targ);
	bool	Fighting(Mob* targ);
 to
	Code:
		void	ClearFeignAggro(Mob* targ);
	// Everhood 6/17/06
	void	ClearZoneFeignAggro(Client* targ);
	bool	Fighting(Mob* targ);
 entity.cpp
Add 
	Code:
	// 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();
	}
}