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();
}
}