PDA

View Full Version : Working towards Animal Instincts in NPCs


ScotchTape
03-25-2002, 10:35 AM
This is a divergent view from eqlive. Purists should skip this thread. I'm hashing it out here because, I don't quite have access to the tools I need to do any development work. It'll be ultimately up to the base maintainers if they want to include this.Regardless, I plan on putting in a flag to turn such experiments on/off.

The goal is to put in place some instincts for the critters that walk about the face of norrath. For example, a hungry wolf will attack, while a full wolf may not. Secondly, I've always viewed a zone as a kind of fishbowl and I'd like to make my fish do stupid tricks.

The first part of this is going to introduce hunger code for NPCs. It is a rather primative instinct. Either you are hungry or you aren't. And there are thresholds, such as being stuffed full makes you cranky, and not eating enough makes you cranky, but eating just the right amount makes you (generally) healthy, wealthy, and wise.

I'm thinking a simple struct, a struct so I can easily expand it later, might look like

NPC
class
{
protected:
struct_AnimalInstincts* AnimalInstincts;
}

struct struct_AnimalInstincts
{
sint8 Hunger;
};


-100 < Hunger < 100

With 0 being equilibrium.

Now if you're hungry (hunger < 0), then you need food. I'm thinking that if you give the item (check Consume_Struct), then you are hungry. Next, we need a command in (i think client.cpp) that processes the command #Hungry?

If an NPC is Hungry, it tells you as much. If not, then not.
(need pseudo code script ;)

//isnpc check and stuff
Message(0, "Hunger: %i", target->AnimalInstincts->Hunger);

Message(0, "I need no food.");
or
Message(0, "I need food. Feed me!");



Now we need to feed the fish. I'm thinking a fish is fed when four food items, nonstacked, are given to it. This has the effect of possibly raising the hunger of the npc by something like rand() % 2 == 1 ? 1 : 0. 'course, there will need to be bounds checking with max(100) and min(-100).

Now, over time the NPC will go hungry. So, their hunger should be increased (which actually decreases the Hunger value). At some point, this should probably work off the existing eat-food timer, but for testing I want all my NPCs to starve.

Which brings in the second command for client.cpp: #StrikeFamineInZone which causes all the npcs hunger to drop to -100.

This doesn't classify itself as an instinct quite yet, and I'm fearful of putting in any kind of silly check such as (if Hungry, go find food!) as all the NPCs will flock to the first available food source... rather, instead, I have two ideas I'm kicking around. The first goes back to the healthy, wealthy, and wise argument.

If an NPC is fed well, we'll say 0 < hunger < 50, then

a. their wisdom score goes up (perhaps skills too, but last I checked these were hardcoded at 252 with a big TODO flocked next to it).
b. their strength score goes up (or maybe minimum damage)
c. they get extra cash ( a few silver or something small)

Alternatively, I'd just like to tint the npcs a different color. However, I don't know if the client supports this.

Malevolent
03-25-2002, 10:38 AM
Odd. Must have caught a cookie in my login there. Ooopsie.

I don't suppose someone could clear my ScotchTape account, could they?

--MV

Malevolent
03-26-2002, 02:49 AM
Woot. 2.6 was released today! :-)

Aside from accepting gifts from players, the above was trivial to implement. So now comes necessarily phase 1+, then 2.

In phase 1+ I need to:
1. Move the above instinct core code into 2.6
2. get that working
3. Move on to phase 2

Phase::2

Being hungry is only part of it. Animals fall into three different categories. You either eat meat, eat vegies, or eat both. Eating meat means you have a tendency to eat N/PCs. Eating vegies makes you hungry and docile. Maybe if item population in the zone (item droppings) work, then sprinkling vegies about the area to have NPCs go after them. (Smells like I'm cooking part 2) If you eat both, then you're moody, but are prone to eat the N/PC. Alright, so omnivore might be a bit more complicated to do right now, so we'll just deal with the core two: carni and herbi -vores.

I'm going to add in the animal instinct struct a member possible values (0,-1,1) that designates whether I am a carnivore (0), herbivore (-1), or omnivore (1). So (1) isn't going to be used for a bit, but it will be used so a bool won't work.

Carnivore:

When a NPC "eats" a PC, it calls NPC::Eat() and increments by the level of the PC. If it is another NPC, then perhaps the same.

Now what I find interesting is that I'm going to try to aggro against NPCs. Cannibalistic goblins. Oh yeah! Potential problem: what happens if zone aggros against one another and the entire place goes nuts? So maybe only eat your fellow if you are below, say -50.

I don't think the attack code currently allows for NPCs to attack one another. I might have to modify this.

Herbivore:

Sprinkling items about the zone, such as vegies, is necessary for this to work. Once that is possible, sprinkle the items about the zone and have the various NPCs path to their location. Nothing fancy here, just slowly move the NPC in the direction of the item. e.g., set NPC eventual destination == item location. They only need one, and no two NPCs should get the same item (prevention of another problem).

Omnivore:

Does both. Can't do this without the first two, so looks like I'll save this until later.

That's a good start for the game plan tonight (hoping), if not, then sometime this week. :)

--MV

Trumpcard
03-26-2002, 03:32 AM
I love the idea !

I would set a true false value in the variables table though

AnimalAI 0/1 though..

Some people might not want their animals all following instinctual pattens. Plus, Im thinking that running the AI on all the zone animals might be a bit CPU intensive, especially in big zones like the karanas.

While you are emulating natural patterns..

You could even put sleep code in... If they are asleep, you have a random chance of wakening them if you come within a certain radius, but if you sneak by, you get an attack bonus, or you can just run by them without agro'ing. (sleep would lower their agro radius to 0 in essence).

Hmm
03-26-2002, 04:59 AM
it should be 0 to 3.

zero no animial effect ( ie: rock golems )
one veggie eater
two meat eater
three both

Baltar
03-26-2002, 06:27 AM
man this is an awesome idea! good work and good luck. Instincts opens the world to so many kewl possibilities.

Malevolent
03-26-2002, 06:56 AM
it should be 0 to 3.

zero no animial effect ( ie: rock golems )
one veggie eater
two meat eater
three both

Excellent point. Then maybe later rock golems may eat ..erm.. rocks? :-)

4 - rocks

Baron Sprite
03-26-2002, 10:35 AM
good idea would be to have npc animals eat each other too, following some kind of food chain, don't know if you said that but I missed it...
also: If an animal with rabies bites another one, it gets rabies... ect...

Trumpcard
03-26-2002, 10:47 AM
Make a new database field, food chain level, where a creature will attack anything else with a lower food chain number but ignore, stay away from anything with a higher one.

It might be fun watching a bunch of animals chasing each other around south karana, but it would lead to very erratic behavior as everything started running from one another and never stopped to eat.. It'd look like the playground at mcdonalds...

Baron Sprite
03-26-2002, 11:21 AM
well if something bigger wasn't hungry it could ignore it or if something was a jerk it would kill anything it saw that was lower on the food chain, IE a giant would smash a bunny into goo if it saw it :D or something to that effect.

Hmm
03-26-2002, 01:39 PM
ahh thats very good idea!

maybe 2 variables.or a table.. if its veggie eater some plants is uneatable ( like high level plants like trents)

or meat eater ie: wolf dont try to eat bear.

Hmm
03-26-2002, 01:41 PM
doh didnt see previous suggestion sorry heh

hogger
03-26-2002, 03:24 PM
Yeah, I've got no idea how you'd do it, but those hunting animals should eventually give up the chase too. Could you imagine trying to camp a spawn that won't stop chasing a ribbit that it can't catch...

Malevolent
03-26-2002, 04:38 PM
I decided against using an integer to represent what kind of thing a mob is (meat/vegie, etc.) and so settled on using boolean on whether

1. do you eat meat T/F
2. do you eat vegies T/F

Which pretty much get the vast majority of cases I could think of and since they're in the struct, it wouldn't take much to expand it later.

There was also the issue of expressing whether a mob is a meat or is a vegie.

1. i am meat T/F
2. i am vegie T/F

Same kind of thing, as described above, is happening here.

before I sat down to code this, the integer idea seemed like the way to go. Then i started looking at the chaos I'd have to deal with and decided some boolean checks would get the job done and be easier to put in place. And, as a bonus, might conserve on resources more than a sint8 (or whatever).

If my theory holds true, these simpler pieces, when and once assembled, will create a nifty illusion. Still a little while to go though :-)

todo/notes:

mobs have properties of animalinstincts, but not methods like npcs

if the player doesn't have a target selected, then the npc can't eat (so if a player unselects target before death, then npc can't feast on body)
::Starve() needs done (just reverse of Eat but w/o having to do -'s)
need to think about what kind of benefits should fall onto a mob for having good health. For example, maybe if you aren't hungry then your stun timer doesn't last as long. And if you are hungry, then it lasts longer.

Phase 3 will consist of a few things that I pushed aside in p2. Namely, messing around with players giving npcs items and having that translate to food for the npc. Note to self: OP_Click_Give.

Anyhow, here's the bulk of phase 2 (I expect to amend this later), which is more proof of concept groundwork:



npc.h

//malevolent
struct strctAnimalInstincts
{
sint8 Hunger; // -100<x<100 : 0 equilibrium [threshold]

bool Meat; //do you eat meat?
bool Vegetables; //do you eat vegetables?
};

class:

//************************************************** ***************//
//Animal instincts: Hunger

void Eat(int HowMuchFood); //malevolent: eat
void Starve(int FastAmount);//malevolent: start
int GetHungerStatus() { return AnimalInstincts->Hunger;}
bool IsHungry(); //malevolent: checks to see if the npc is hungry


//************************************************** ***************//

Protected:
//Malevolent: Animal Instincts
strctAnimalInstincts* AnimalInstincts;


npc.cpp


//malevolent:: is the critter hungry? returns the int value representing their hunger
bool NPC::IsHungry()
{
if (this->AnimalInstincts->Hunger >= 0)
return false;
else
return true;
}

//This should fire after npc has eaten
void NPC::Eat(int amount)
{
strctAnimalInstincts* instincts=new strctAnimalInstincts;
instincts->Hunger=this->AnimalInstincts->Hunger + amount;

//bounds checks

//max
if (instincts->Hunger >100)
instincts->Hunger =100;

//min
if (instincts->Hunger <-100)
instincts->Hunger =-100;

//now assign
this->AnimalInstincts=instincts;

}

mob.h

public:
//*****************************************
//malevolent
bool IsMeat(){return foodtype->IsMeat;}
bool IsVegie(){return foodtype->IsVegie;}
//*******************************************

protected:
//malevolent:
FoodType* foodtype; //what kind of food am i?

//Malevolent animal instincts
struct FoodType {
bool IsMeat; //is a meat-based mob
bool IsVegie; //is a vegie-based mob
};

mob.cpp

in constructor:
//malevolent
FoodType* ft = new FoodType;
ft->IsMeat=true;
ft->IsVegie=false;
this->foodtype=ft;

client.cpp

//Malevolent
//hunger look up on target NPC
else if (strcasecmp(sep.arg[0], "#Hungry") == 0)
{

if (target != 0 && target->IsNPC())
{
Message(0,"Asking target if they are hungry..");

switch(target->CastToNPC()->IsHungry())
{
case false:
Message(0,"Hungry!");
break;
case true:
Message(0,"Not hungry.");
break;
default:
Message(0, "Does not eat.");
break;
}


}
}
//Malevolent
//ForceFeed the NPC
else if (strcasecmp(sep.arg[0], "#ForceFeed") == 0)
{

if (target != 0 && target->IsNPC())
{
target->CastToNPC()->Eat(atoi(sep.arg[1]));
Message(0,"Fed: %i",atoi(sep.arg[1]));
}
}
//Malevolent
//Lookup the NPC's instinct values
else if (strcasecmp(sep.arg[0], "#HungerThreshold") == 0)
{

if (target != 0 && target->IsNPC())
{

Message(0,"Hunger Value: %i",target->CastToNPC()->GetHungerStatus());
}
}

//Malevolent
//Check to see if the npc can eat the user
else if (strcasecmp(sep.arg[0], "#CanYouEatMe") == 0)
{
if (target !=0 && (target->IsNPC() || target->IsMob()) )
{
if(target->CastToNPC()->CanIEatYou(this->CastToMob()))
{
Message(0, "Yum, yum! I can eat you..");

if(target->CastToNPC()->IsHungry())
Message(0, "I'm going to eat you!");
else
Message(0, "I'm fine and full. I won't eat you.");

}

}
else
{
Message(0, "You really think that such a thing could eat?");
}


}

//Malevolent
//Check on whether they are meat or vegie
else if (strcasecmp(sep.arg[0], "#voretype") == 0)
{
if (target !=0 && (target->IsNPC() || target->IsMob()) )
{
if(target->IsMeat())
Message(0,"I'm meat.");
else
Message(0,"I'm not meat. Move along.");

if(target->IsVegie())
Message(0,"I'm vegie.");
else
Message(0,"I'm not a vegie. You really think I'm green?");
}


}

//Malevolent
//Check to see if the npc can eat the user
else if (strcasecmp(sep.arg[0], "#EatMe") == 0)
{
if (target !=0 && (target->IsNPC()))
{
if(target->CastToNPC()->CanIEatYou(this->CastToMob()))
{
Message(0, "mmmm..foood");

if(target->CastToNPC()->IsHungry())
{
Message(0, "I'm going to eat you!");
target->CastToNPC()->AddToHateList(this,100); //be sure to *stick* to the target
target->CastToNPC()->Attack(this); //attack 'm!
}
else
{
Message(0, "I'm fine and full. I won't eat you.");
}

} else
{
Message(0, "%s says, \"I cannot eat you. You sure people eat your kind?.\"",target->GetName());
}

}
else
{
Message(0, "You really think that such a thing could eat?");
}


}

//malevolent
//using sic code, but adds if npc is hungry and if it can eat the target
//todo add a method to npc with a sicifhungry() signature
else if (strcasecmp(sep.arg[0], "#sicifhungry") == 0)
{
if (target && target->IsNPC() && sep.arg[1] != 0)
{
Mob* sictar = entity_list.GetMob(sep.arg[1]);

if (sictar)
{
if(target->CastToNPC()->CanIEatYou(this->CastToMob()))
{
Message(0, "mmmm..foood");

if(target->CastToNPC()->IsHungry())
{
Message(0, "I'm going to eat you!");
target->CastToNPC()->AddToHateList(sictar,100); //be sure to *stick* to the target
target->CastToNPC()->Attack(this); //attack 'm!
}
else
{
Message(0, "I'm full. I won't eat.");
}
}
}
else
{
Message(0, "Error: %s not found", sep.arg[1]);
}
}
else
{
Message(0, "Usage: (needs NPC targeted) #sic targetname");
}
}



attack.cpp
::death
at end of the tunnel

//malevolent
if (other->IsNPC())
other->CastToNPC()->Eat(pp.level);


--MV

Malevolent
03-26-2002, 04:45 PM
Yeah, I've got no idea how you'd do it, but those hunting animals should eventually give up the chase too. Could you imagine trying to camp a spawn that won't stop chasing a ribbit that it can't catch...

I'm assuming that the attack code (which is my effective means of eating something) has a combat timer. I remember seeing a timer or two in there. If I'm wrong, then it'd just be a matter of taking the hate code and slowly decreasing it over time. I think.

hrm. I assumed that such a check was already in there. However, looking quickly through npc.cpp, suggests that I might be wrong. Blimey. I'll have to take a peek at that tomorrow.

--MV

Malevolent
03-27-2002, 01:58 AM
Added these commands:

#Hungry
#ForceFeed
#HungerThreshold
#CanYouEatMe
#voretype
#EatMe
#sicifhungry

#Hungry

Informs the user as to whether or not the selected target is hungry.

#ForceFeed

Feed the target x amount, where -100<=x<=100

#HungerThreshold

Returns the current hunger value as defined in the struct as Hunger (also -100<=x<=100)

#CanYouEatMe

Informs the client whether or not the target is capable of eating you.

#voretype

Informs the client whether or not the target is a carnivore, herbivore, or none of the above.

#EatMe

If hungry, the selected target will attack you. At death, consume you for your level worth of food.

#sicifhungry

If hungry, the selected target will go after the identified N/PC.

Zio
03-27-2002, 06:25 AM
Very cool :p

Malevolent
03-27-2002, 10:37 AM
"They say the world is round. They say that men have been to the moon and back. They even say that men have conquered the mountains, the land, and the sea. Gnollfur! it just isn't fair. What about the dark alleys of Qeynos, anyone tried that yet? No? Great! Wait - Is it dangerous? Yes? Drat."
- Freeport Scout

Phase Three

Add something to do decay on the hate list (e.g, a decay timer). Right now, from what I've seen of the code, there isn't really a decay timer until something triggers it off. It's pretty important, like someone pointed out earlier, that mobs give up on the chase at some point. The only adverse side effect right now, which is pretty adverse, is that the mob might just give up attacking while another entity is attacking it. But, I believe the attack code has hate-adding code in it.

So, in effect, I'm thinking a timer that lasts for a minute or so before popping off the top hate for the npc is needed.

Speaking of timers, there is going to be a timer for deciding when the NPC should eat. After an elapsed time (t), an NPC will loose a hunger point if they eat either meat or vegie.

For now, I'm thinking the arrangement will be

Increase Hunger by:
Eats Meat: 2 points
Eats Vegies: 1 point

And if hunger is below the threshold (-50), then find something in the zone that you *can* eat and go after it (ob: this will evolve into pack code later).

Now that you can eat things, there is the team aspect. You wouldn't want to eat something that is on your team. By the same token, your team should go after its food sources together when under certain conditions (see ob: note earlier, might bump this until later). The important thing here is that we don't want to eat team members because we are team players.

So, we need to call this->GetFactionID and do some checks. Does faction id point to a relation of factions somewhere or does it point to only one? Tinkering with this will produce the desired "don't eat me, I'm on your side! result". Which will need to be in the same place the target selector check is.

I also need to find out what the status is on items dropped in the zone. That should just spawn a mob or entity (can entities be spawned?) into the zone. But then there's the matter of picking the item up, etc, etc. I might table this in favor of pack code.

--MV

Hmm
03-27-2002, 12:28 PM
hmm if player got eaten corpse should change to dead skellie. after all bones usually dont get eaten.

hogger
03-27-2002, 12:59 PM
You know, this same principal could be applied to a social 'food chain'. For example an Orc Centurian offs a goblin whelp for his cash just because he's tougher and he's evil and no other goblins are around. It's sort of a Tolkien-ian idea.

Malevolent
03-27-2002, 01:25 PM
You know, this same principal could be applied to a social 'food chain'. For example an Orc Centurian offs a goblin whelp for his cash just because he's tougher and he's evil and no other goblins are around. It's sort of a Tolkien-ian idea.

Quite correct. As a matter of fact, the principles I'm using to build this take into account the spirited aspect of life too -- the same power that influences hunger, also influences greed. I have in mind to create thieves that seek out the rich and plunder from them at some point down the road. So with luck we'll see exactly what you're talking about, and a little change on the side ;)

My larger goal is not to hard code the 'chain' at all. And based on my most recent results.. this appears to work. Still doing trials though, so it is still too early to say for sure.

Malevolent
03-28-2002, 10:44 AM
Some lessons learned so far:

1. Corpse checking. This is important. See attached screenshots.
2. If you are the only client, then not having the npcs put you on their hunger list is also important.
3. See 1.
4. Social hierarchies form naturally through a simple 'is he stronger than me' check, which for those of equal level create small packs

Some things I've noted that need corrected:

1. NPC movement needs help
2. Bouncing NPCs need to remember the world needs gravity. Its their for a reason, use it.
3. The agro list needs a bounds check. I've seen it > 12000 (this morning, actually). Likely the design I have going, but still should be a check for people who mess it up (like mua). :)
4. NPCs do not need to be on their target's coordinates (so far as the client is concerned), just 'near' them.
5. NPCs have a tendency to group at certain 'hotspots' in the zone. I can think of a handful of reasons why, and mostly my fault too.

Hmm
03-28-2002, 03:24 PM
text in ( ) is my comments

1. NPC movement needs help ( yeah it runs too slow, like overweight walking. )
2. Bouncing NPCs need to remember the world needs gravity. Its their for a reason, use it. ( its getting rare but there should be "fall and stay on floor" code. )
3. The agro list needs a bounds check. I've seen it > 12000 (this morning, actually). Likely the design I have going, but still should be a check for people who mess it up (like mua). :) ( no comment :) )
4. NPCs do not need to be on their target's coordinates (so far as the client is concerned), just 'near' them. ( yeah should add "near enough" code. pet has same problem )
5. NPCs have a tendency to group at certain 'hotspots' in the zone. I can think of a handful of reasons why, and mostly my fault too. ( no comment )

Malevolent
03-29-2002, 01:51 AM
Bouncing NPCs seem to only be a problem in zones where they start off in high locations (e.g., kelethin) or when the agro limit reaches 200 or so. The h (z?) coordinate doesnt' seem to work server side, or if it does, it isn't updating the #loc command. E.g., an orc oracle chases an elf slave into the water, promptly kills it, then swims back to home -- only gets stuck. Putting the client next to the orc, it is h:-37.5, whereas the mob has a h(z) of -61.

This example actually goes onto something I wanted to speak about today, which are the test results of yesterday.

Test Results

Permafrost

Goblins run through the maze looking for anything they can eat. As do the wolves (which oddly enough travel together in a pack, maybe b/c of their relative zone entry point nearness?). As does vox. Vox, unfortunately, gets stuck in the small tunnels. I should have tried changing her size, now that I think about it. I made a few sacrifices for her, but the goblins would come running up and KS from her.

Crushbone

The orcs took over the zone. Literally. Dvinn was quickly surrounded and killed on the bridge, while the slavers and others chased the slaves around until they were dead. Spawning an elf on the bridge results in a bunch of hungry orcs coming in after it.

GreaterFaydark

There is a problem with hoppers in this zone. The zone is so large that it is really difficult to tell what is going on. However, spawning a highelf in kelethin prompts the nearest wood elf to come near and kill it. I don't know the result of the orc/elf war. I have a feeling the elves won (what with all the decaying orc corpse messages :)

east commons

Spawned six liches (Miguel (sp) in a circle. I put then inside a bunch of human druid spawns named 'sacrifice'. When the liches got hungry, it turned into a royal rumble at the tunnel entrance. I let it run all night -- the liches appeared to have held out, although a couple did die somehow. I didn't note any zone hopping here.

All in all, I'd have to say it works.

There are some things that do need changed. For instance, all the NPCs are hardcoded as meat eaters which has a -2 penalty. They are also all hardcoded as meat. I'd like to just swap this out and make it dynamic, but I might wait until 2.7 for that to happen (what with all the new db changes coming). I'd also like to add a series of other properties for the mob, that way a mob may ignore faction, corpse, race, level (which gets interesting), checks before consuming something.

Then there is the next step. I'm torn if I want to work on the thief code (does pickpocket work yet?) or add in the next layer for the ai. With the thief code, I could flag mobs to come track you down if you have x amount of money, and attempt to pickpocket it from you. 'course, if they track you down and you're KOS, then they'd kill you too. The next layer of ai, which I might do if pickpocket isn't working, involves a slight reordering of some things.

For example, with level checks, an implied social order is created. I want to build off this some more. Given X, with 2Y (imagine X as the top node, 2Y as 2 nodes below) I want 2Y to take the kill and give a % of that kill to X, which would be their master. Then, if 2Y has contributed ($a) amount, then X will act as a kind of guardian for them. If 2Y(me) is in trouble, then X will come over and help.

Doesn't seem to be that difficult and may actually be better to do this first because then I could put in guild-code for thieves. If you pick on a thief and they're popular in the guild ($a), then the guild comes after you. I see in the code that it is possible to zone npcs across, or suggests that it is, so this shouldn't be very difficult either.

--MV

Malevolent
03-29-2002, 03:21 AM
If you've read the above, then you have a pretty reasonable idea as to what to expect from using these files (and what is in them). Therefore, I take and assume no responsibility for you using these and really screwing up your own hard work in your eq world.

--MV

Trumpcard
03-29-2002, 03:27 AM
You read my mind Male! I was hoping you would post your changes so I could try to compile it in! I'll give it a shot on my server, Wasted Earth and see how it looks..

update:Just recompiled with your changes.. Everything compiled with no problems. If anyone wants to check it out in action, log onto to The Wasted Earth and post your observations..

Now if I can just overcome my NAT logging in problems...

Baltar
03-29-2002, 07:24 AM
Wow read the description and am still amazed. Great work Malevolent! Any chance of integrating this into the later releases?
Only downfall I see to this is on the low end servers this will cause severe cpu load if someone goes crazy on the mobs. But if you limit the ai to certain npcs, it can be controllable.

Malevolent
03-29-2002, 07:26 AM
Reminds me of a couple small caveats to look out for.

1. It will not eat the client, no matter what you do. I disabled it. Having the entire zone come after you because it is hungry isn't much fun.

2. Zonefamine isn't implemented (on my todo list with zoneheal, zonedeath, etc.)

3. I don't remember what aspects I have commented out, but I do think that the code above (*points to the attached file in his former post*) igornes the faction and level check. Faction needs some work -- there needs to be a ::AmIAFriend faction method check that returns bool versus just using the factionid.

4. I increased the timer for span between decriments in the hunger threshold. So it will take longer for something to get hungry. However, once something is hungry and you want to know what it is going after, use #GetTarget (or #gettarget). If you're impatient, use the #ForceFeed command like so

#ForceFeed -100

--MV

septimus
03-29-2002, 10:51 AM
Wow! I have to say these ideas have gobsmacked me, Malevolent!

It's true genius in the ideas and implementations such as these that really give EQ that much needed push in the right direction. While Verant continue to bulk EQ out with new zones, new NPCs and new items (and the occasional - and seldom - bright idea), you've came up with something that really changes the way the world would work, and make the experience far more immersive.

Stuff like this could eventually fruit into true NPC interaction, animals could hunt in packs on their own dynamically generated territory, reproduce, be affected by weather and even seasons. There could be food chains that would be affected by environmental impacts, and PC interference. You could build social structures into towns and settlements of people to allow NPCs to have friends, enemies and favorite places. For instance, a group of guards who like to hang out after hours at a bar (Which then suggests social obligations like jobs - maybe the guards get payed for their duties to the town, and maybe one gets a pay rise and buys the rounds? And they get drunk, fool around and turn up late the following morning? Hehe ok maybe I'm getting ahead of myself here :P)

All these things are possible because of the much smaller scale of this project, and I look forward to seeing a better EQ experience that fruit from these first steps :)

I await further posts from you with baited breath :)

Hmm
03-29-2002, 04:56 PM
whooo nice! i cant see the result of changes once its done in west karana south karana etc.. what with all mobs there ( eleplant etc )

Malevolent
03-29-2002, 05:37 PM
I popped over to south karana tonight for a bit. Looks like the hatedecay code I have in there is a bit of a drawback for larger zones. The gnoll I was watching went back and forth, back and forth, but it did stop to kill the human I spawned near it.

So it goes. In the entity.cpp file you'll find commented lines which when uncommented check for level and faction in addition to the other checks already mentioend elsewhere. The filein the zip file does not make these checks. It only checks ti ensure the race is not the same.

It shouldn't make much difference outside of the patterns of organization that you may observe.

E.g., in erudsxing, hojo has gone hunting for a giant pirana. Alas, the hate timer slows him down a bit. I'm not sure I want to turn this off, as it gives the impression that they are fighting their hunger. I might slow it down a bit. We'll see when I get back to it here in a couple days.

--MV

Drawde
03-30-2002, 05:51 AM
Has anyone here played Nethack? It's a Diablo-esque dungeon crawl RPG ,very basic graphically (originally text-based, now isometric or top-down 2D) but with the most complex and detailed object and NPC interaction system I've seen in any RPG. For example all the monsters in the game, including your pets/familiars, need to eat - some are carnivores, some herbivores and there are also lithivores/metallivores that eat metallic objects.. you can even polymorph yourself into a metallivore then eat magic rings to gain their stat increases!
It'd be great if EQ could have some of that depth, though the hard-coded interface might restrict how much can be added.

Hmm
03-30-2002, 08:20 AM
things that could be done..


1: hunting packs. set it as group spawn when gnolls in south karana is hungry then it goes around looking for food. if it kills a eleplant they "bring" it to gnolls splitpaw and gnolls in there get sated. they may possibly hunt and kill a player thats kos to them. ( somehow informing splitpaw gnolls since theyre in seprate zone with NOTHING to hunt... )

2: smarter player species or npcs based on em ( ie: coldian ) they dont stand there forever, and if hungry, walks to nearest food store and buys food. it would make cities MUCH realistic. make em haggle sometimes maybe lol..

3: find how to make plants. maybe very small trees or trents? that will be problem that has plant eaters and no plant models.

Malevolent
03-31-2002, 08:31 AM
A couple design notes.

I have working master-servant code. Currently, you have two options. First, you can depop then repop the zone, which will flag everyone in the zone to look at you as their master. Or, you can use the #spawn command to bring in your own half-pets (not sure what to call these things).

As master of a zone, or small group of NPCs, when famine strikes and blood boils, and then NPCs die you receive a cut. Right now, I have that money routed to the client's bank account. I'm having a heck of a time getting the client to update how much money is in the bank or in the player's inventory (I've got to be missing something obvious), so a zone is required to see how much you have accumulated so far.

E.g., I depop the zone. Then repop it. Here is some old chat lines from a version or so back.


[Sat Mar 30 11:44:57 2002] Loyal Commando punches orc emissary for 46 points of damage.
[Sat Mar 30 11:44:57 2002] Orc emissary hits Loyal Commando for 51 points of damage.
[Sat Mar 30 11:44:59 2002] Loyal Commando punches orc emissary for 43 points of damage.
[Sat Mar 30 11:44:59 2002] orc emissary has been slain by Loyal Commando!
[Sat Mar 30 11:44:59 2002] Master, I your loyal servant Loyal_Commando01, have donated 26 food now of a total of 26 food parts to you!
[Sat Mar 30 11:44:59 2002] Master, I your loyal servant Loyal_Commando01, have brought money!
[Sat Mar 30 11:44:59 2002] I shall now donate to you 0 platinum, 5 gold, 2 silver, and 6 copper.
[Sat Mar 30 11:45:05 2002] Orc oracle hits Loyal Commando for 20 points of damage.
...


He later died. However, on a more interesting note is this snippet. It gives an example of one of a couple of the commands I've added.


[Sat Mar 30 11:45:37 2002] You say, 'Hail, Loyal Commando'
[Sat Mar 30 11:45:40 2002] You say, 'DO NOT FAIL ME'
[Sat Mar 30 11:46:53 2002] You say, '#gettarget'
[Sat Mar 30 11:46:56 2002] You say, '#getmaster'
[Sat Mar 30 11:46:56 2002] I obey my master Tavin, have you heard of them?
[Sat Mar 30 11:46:56 2002] I don't know how much I've donated
[Sat Mar 30 11:46:57 2002] You say, '#hungry'
[Sat Mar 30 11:46:57 2002] Asking target if they are hungry..
[Sat Mar 30 11:46:57 2002] Hungry!
[Sat Mar 30 11:46:58 2002] You say, '#hungerthreshold'
[Sat Mar 30 11:46:58 2002] Hunger Value: -52
[Sat Mar 30 11:46:59 2002] You say, '#gettarget'
[Sat Mar 30 11:46:59 2002] I must find Ambassador_DVinn00, so that I may eat them.
[Sat Mar 30 11:47:38 2002] Loyal Commando says, 'Master, I have failed you. I shall await you in heaven.'


That last statement is sent to the servant's master whenever they die.

Some other adjustments include making hunger not trigger the entire zone. And some general reordering of things in preparation for the next steps.

I'll discuss this more tomorrow.

-MV

Malevolent
04-01-2002, 02:54 AM
I think that I mentioned last night that I had reduced the zone aggro for hungry mobs. I'll be subsequently removing it, or flagging it somewhere, as it will soon be causing the next layer or two of pseudo-instincts to be unbalanced.

I've got a better description as to what I'm working on over at the AI Thread (http://forums.eqemu.net/showthread.php?s=&threadid=1028), so I'm going to go over some of the technical difficulties I've been finding myself beating my head over lately.

As I've mentioned, I've been having some problems sending a player update packet back down the way to the client. The only way to know how much money you have in the bank after having attained zone mastery status is to zone. However, since I plan on eventually putting a proxy mob to follow masters that handles this reporting, I'm just going to ignore it as a problem. It has already eaten way to much of my time.

This week I plan on tracking down the last bug(s) with the master code for the client. The only bugs that I've noted thus far are a memory leak, random zone dump, and sometimes disconnect on zone boot. The latter I can deal with, the former are problematic.

I'll also be adding one additional layer to donations to permit experience donation.

Right now, the master-servant code looks like Y=Y or Y=X(n) where N(lim 0-># mobs in zone). I'll be changing this once the above is corrected to give the following two possibilities:

P1: (type)Y = (type)Y //selfmastery
P2: (type)Y <- X((type)N)

which then zone will contain an indeterminate number of (type)Y with an indeterminate number of X((type)N). I see I'm going to need to put in a #zonemastercheck command, in addition to a #zoneservantcheck. It could get tedious walking around asking each NPC what their #GetMaster is.

That, I view, as a fairly each task (knock on wood) to do. Next comes up the issue of 'click protection'. For masters, their hunger cap will max out for the size of the hunger type. I think its sint8, so what -128, 128? I might be changing that value type soon. However, I'm not sure I want a SInt16.

I wanted to wait, but the only way to check on this with any reliability is to introduce the commands #accountbalance and the like for a mob target. Which puts me that much closer to having my own scribe follow me about. Half-pets are cool :)

--MV

Malevolent
04-02-2002, 03:10 AM
I've wrapped up a bit of fun code, which will connect in with the donation task for the mastery aspect that has henceforth been discussed.

The logic for this is pretty simple, but should achieve the desired result. In a nutshell, it looks like this:

If I'm a bard or a rogue, and I'm ready to go collect some money, then I'll search the zone for a wealthy man, and hunt them down, to take that money and put it in my own pocket.

The mob in question sends you a message before it comes looking for you. The current qualification for being rich? 50pp. If the client dies, then all of the player's money is pushed onto the killing mob (if that was the intention), except for 1 copper (the trademark of rogues on norrath).

Right now it attacks the client, but I'd like to make use of PICK_POCKETS at some later point.

I also have a few signatures in place for a bard to do something similar to /follow. I have a neat idea for this, but it depends on the status of the method(s) that 'accept money from targeted player' (haven't looked).

--MV

Shawn319
04-02-2002, 03:51 AM
Malevolent, Why dont you join the chat room sometime?