Log in

View Full Version : Feign Death Code - Revised


Wiz
10-24-2002, 06:41 PM
This is a complete code snippet for Feign Death, including aggro clearing, enemy memory, and such.

To initiate, open client_process.cpp, and insert this under the opcodes.


case OP_FeignDeath:
{
int16 feignskill = GetSkill(FEIGN_DEATH);
int16 primfeign = feignskill;
int16 secfeign = feignskill;
if (primfeign > 100)
{
primfeign = 100;
secfeign = secfeign - 100;
secfeign = secfeign / 2;
}
else
secfeign = 0;
int16 totalfeign = primfeign + secfeign;
if (rand()%160 > totalfeign)
{
SetFeigned(false);
entity_list.MessageClose(this,false,200,0,"%s has fallen to the ground.",this->GetName());
}
else
{
SetFeigned(true);
entity_list.ClearFeignAggro(this);
}
if (rand()%300 > feignskill && rand()%4 == 1 && feignskill < 200 && feignskill < GetLevel()*5+5)
{
SetSkill(25,++pp.skills[25]);
UpdateWho();
}
break;
}


Now, go further up in client_process.cpp, find OP_SpawnAppearance. Under standing, sitting, looting and ducking, insert

SetFeigned(false);

Insert this into client.h:


void SetFeigned(bool in_feigned);
bool GetFeigned() {return feigned;}
bool feigned;


Insert this into Client::Client in client.cpp

feigned=false;

And this at the bottom of client.cpp


void Client::SetFeigned(bool in_feigned) {
if (in_feigned)
SetPet(0); //Crashes unless this is put here
feigned=in_feigned;
}


Insert into npc.h


void SetFeignMemory(const char* num) {feign_memory = num;}
const char* feign_memory;
int8 forgetchance;
Timer* forget_timer;


Insert into npc.cpp, in NPC::NPC


feign_memory = "0";
forget_timer = new Timer(500);
forgetchance = 0;


Insert into npc.cpp, at the bottom of Process();


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 = forgetchance + 5;
}
}
else
{
SetFeignMemory("0");
}
}


Insert into entity.h:

void ClearFeignAggro(Mob* targ);

Insert into entity.cpp:


void EntityList::ClearFeignAggro(Mob* targ)
{
LinkedListIterator<Entity*> iterator(list);
iterator.Reset();
while(iterator.MoreElements())
{
if (iterator.GetData()->IsNPC() && 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();
}
}


In NpcAI.cpp, find this line:

sender->AddToHateList(currentmob,1);


A bit above it, in the if statement, add && !currentmob->CastToClient()->GetFeigned() to prevent mobs from aggroing a feigned person.

Insert this into spells.cpp, under SpellEffect:


if (spells[spell_id].goodEffect == 0 && this->IsClient() && this->CastToClient()->GetFeigned()) {
this->CastToClient()->Message(MT_Shout,"You are no longer feigning death because a spell hit you!");
this->CastToClient()->SetFeigned(false);
}


Finally, insert into spells.cpp, under SE_FeignDeath:

this->CastToClient()->SetFeigned(true);
entity_list.ClearFeignAggro(this);


You're done! Yeah, it doesn't work exactly like VI's rather fucked up feign death code, but here's the advantages:

- Easier processing. Having a purely time based forget chance eliminates some of the more comical aspects to VI's FD, and can also be modified per NPC through a database, if some tweaking is done.

- You don't have to turn off autoattack for this feign to work (Never understood that anyways).

- No feign bug, at all. This feign always works when successfully processed.

Wiz
10-24-2002, 06:45 PM
Oh, yeah. This needs to be added to hate_list.cpp:


bool HateList::IsOnList(Mob* targ)
{
HateListElement *current = first;

if (first == 0) {
return false;
}

int r = ElementCount;
for (int i=0; i < r; i++) {
if (current && current->GetEnt() == targ) {
return true;
}
current = current->GetNext();
}
return false;
}


This to hate_list.h:


bool IsOnList(Mob* targ);


And this to npc.h:


bool CheckAggro(Mob* other) {return hate_list.IsOnList(other);}


Sorry 'bout that. :P

Xarslik
10-24-2002, 07:03 PM
Very nice wiz, can't wait to test it out on next release. =)

a_Guest03
10-25-2002, 04:10 AM
Very clean and good, Wiz :) Thanks for the feature!

kathgar
10-25-2002, 05:38 AM
You kinda missed the whole they only forget after they walk back to spawn point(we dont' do) and then they alwyas forget unless they are above level 35..

Wiz
10-25-2002, 05:47 AM
Actually kath, level 35 is included. Check again.

Also, they CAN forget without walking back to spawn point, the chance is small - I just did it this way, because I personally like this system better. I don't believe in doing everything exactly as VI has.

I'll just quote the section:


if (iterator.GetData()->CastToMob()->GetLevel() >= 35)
{
iterator.GetData()->CastToNPC()->SetFeignMemory(targ->CastToMob()->GetName());
}

Wiz
10-25-2002, 06:00 AM
Fixed a typo in the code.

But, if you REALLY want a VI clone, here you go:


if (forget_timer->Check() && strcasecmp(GetFeignMemory(),"0") != 0) {
Client* remember_client = entity_list.GetClientByName(GetFeignMemory());
if (remember_client != 0)
{
if (org_x == GetX() && org_y == GetY())
forgetchance = 80;
else
forgetchance = 15;
if (!remember_client->CastToClient()->GetFeigned() && rand()%100 <= forgetchance)
{
AddToHateList(remember_client,1);
SetFeignMemory("0");
forgetchance = 0;
}
else if (!remember_client->CastToClient()->GetFeigned())
{
SetFeignMemory("0");
forgetchance = 0;
}
}
else
{
SetFeignMemory("0");
}
}


Exactly like the VI remember chance. Enjoy. :)

kathgar
10-25-2002, 06:26 AM
Hmm, it sure does.. my bad =P