How to make NPC's "gossip"

Started by
66 comments, last by Gollum 21 years, 2 months ago
You might find a useful idea or two in my implementation of the same ideas. For dissemination of information, each of my NPC''s belongs to one or two circles which is a structure which contains a list of NPC''s who hang out together. For "off-stage" NPC''s, information transfer is handled by updating of the circles, which determines which peices of information are transferred between which members of the circle (Note: the circle update doesn''t bother physically moving NPC''s to the same location in order for them to be able to exchange the information. It looks at the distance between the NPC''s to decide if an info transfer is likely.). This is the main method of information transfer and prevents information from spreading everywhere, although the circle update also includes a small chance that the information will be leaked to the general population in the immediate area.

As for having the NPC''s relate information to the player, I broke down information into several clases: Resource, Ambition, Mission, and Event. These all belong to the base class Subject, and polymorphically over-ride a function called verbalize. I don''t know if Python supports polymorphism, but if it does, then you could have each information node be a Subject, and then call the verbalize method of the node which will express the subject in the appropriate terms.

For example, the Resource verbalize method looks like "(Resource name) is located at (Location) and owned by (owner)", while
the Event verbalize method looks like "(Event instigator) used his (Tool used) to gain (whatever he was after)". (I am working on putting the verbalize functions through some helper functions which would punch up the dialog a little bit).

When an Event occurs (which is the use of one Resource to gain another), an Event object is created, which is immediately noted by all of the witnesses. This would fit in nicely with your idea of characters gaining information from their surroundings.

Sean
"we need common-sense judges who understand that our rights were derived from God. And those are the kind of judges I intend to put on the bench." - GW Bush"no religious Test shall ever be required as a Qualification to any Office or public Trust under the United States." - Article VI of the US Constitution.
Advertisement
quote:Original post by Gollum
Very simple, but it works, and I always program incrementally. My next steps will be to have the knowledge transfer randomized a bit, and to only have it happen when the NPC's run into each other (currently, they don't live on a map or anything, though I have another prog with maps that I can put them into).

- I have read (and it makes sense) that if knowledge spreads too easily, it will reach an equilibrium, where everyone will know everything. Different solutions have been proposed for this. One is some sort of "decay function," which would implement memory loss. I have no idea how to write that. Ideas, Timkin?


A decay function for knowledge:

Nature's typical decay function is the exponential family, so this could be a good place to start. For each NPC assign them a (positive) number a and for each piece of information held by that NPC, assign a time variable t that increments from t=0 when they learn the information. Then use the formula y=e-a t to compute the level of decay. Once this number drops below a given threshold ythr, the information could be considered forgotten and thus deleted from the database. For information that you want to have remembered forever, set ythr=0.

Here's an extension to that idea that incorporates the randomness you seek in conversations. Use decaying probabilities for how likely someone is to discuss something. For all pieces of knowledge that the NPC has, assign a probability that they will discuss it. Ensure that these probabilities are normalised (sum to 1) so that you can easily sample from this distribution. As new information is gained, decrease the probability of discussing older, less important information. Each piece of information would have an individual probabilty function of the exponential form above. Some information will always have a high probability of discussion: perhaps a war, or the latest sermon by a priest. Possibly include a "discuss nothing" piece of information for people that like to listen??? When it comes time to have a conversation, simply sample from this distribution to see what is discussed. Perhaps if the other person discusses the same topic, both have their probabilities reinforced, making that topic the current "gossip" of the town.


quote:Original post by Gollum
My current plan is pretty simple: Have facts classed in a couple of different ways. One classification will be the type of people who know certain facts. This will usually be by profession. For instance, a baker will never know that the MoorHaven theives' guild is at 101 Evil Street. So, a baker can't learn knowledge that is classed as "treacherous," or whatever.


Nice idea. You could possibly extend this along the lines of Sean99's suggestion to include circles of association. If the baker happens to drink at a particular bar in the seedy part of town, or perhaps visits a prostitute that services 'many' clients, or maybe has a brother-in-law that has some shady friends, then perhaps he or she is likely to learn treacherous information with a small probability. Perhaps you could assign a probability of association for each of your classifications of knowledge. If you combined this with the idea of probabilities for discussing individual pieces of knowledge, then you could actually create a joint probability table for classifications and pieces of knowledge. Let's consider, for instance, that this baker has a probability of 0.01 of discussing treacherous information and she happens to know that the MoorHaven Thieve's Guild is at 101 Evil Street, that Greymoon is the head of that Guild and that Greymoon is infact the local barber (perhaps she's having an affair with him!), then you can assign a probability to each of these pieces of information so that they sum to 0.01. Another way to formulate this would be to store the following information:
Pr(discuss(treacherous ))=pt

Pr(discuss(info1)|discuss(treacherous ))=p1
Pr(discuss(info2)|discuss(treacherous ))=p2
.
.
.
Pr(discuss(infon)|discuss(treacherous ))=pn

where

sum{i=1..n}pi=1


Now, to work out what is being discussed roll (your computer dice) to determine if the topic of conversation is about treacherous information. If it is, then roll another dice sampling from the distribution over the pi and discuss the resulting sample. Alternatively, multiply each of the conditional probabilities above by pt to obtain the joint probability table for treacherous information and the pieces of information. Your table would have other entries for these same pieces of information and other classifications. Where the information was not related to that classification, then the probability of discussing it in that class of discussion would be zero.

To take this idea futher, consider that somehow the PCs learn that the baker might have information about the location of the thieve's guild. If asked about this, she would only tell them with probability p=Pr(discuss(location of thieve's guild)|discuss(treacherous ))*Pr(treacherous ). Perhaps the probability of discussing treacherous information depends on who she is talking to. So, the likelihood of her telling the NPCs might be altered by them a) drawing a sword and threatening her; or b) taking her out for a romantic dinner! Either of these may increase or decrease the probability of discussing the particular class of information and thus the particular piece of information. In this case, she took a shine to the big hunky paladin in the front row and thought that if he would just 'off' her lover Greymoon, with whom she had a fight the night before, then she'd be free to have fun with this studmuffin!

quote:Original post by Gollum
- The third point, and maybe most important, is the way I plan to have NPC's get info from their environment. For the most part, I'm not going to have them do it actively. I'll have certain types of events (wars, battles, NPC deaths, changes in the price/availability of goods) generate facts through a function. Then, a second function will look through the new facts and decide who gets them. Make sense? Of course, I am miles away from having a working world with events to generate these facts, but give me time ...


I suspect that this would be more trouble than it's worth. If your world was particulary dynamic then you would need to work out - during the design phase - every piece of information, how it should be classified and who should receive that information. That doesn't sound like an easy task... but then I could be missing an easy simplification of the problem. I would have thought that coming up with an online classification method would not be any more difficult than an offline method.

Well, this post hase gotten a lot longer than I intended... sorry about that! It sounds like you're getting into the thick of things so please keep us informed of your system's performance.

Cheers,

Timkin


Edited by - Timkin on February 5, 2002 8:49:15 PM
I am having lots of fun discussing these ideas, but I fear that until I implement more of them, I''m getting a little in over my head. Here are my thoughts about your latest ideas, Timkin. Please keep in mind that I''m a newbie. My main axioms of programming are these:

- Everything is a fake.
- With that in mind, create the best possible fake of reality, in the least possible processing time.

Now, for the sake of our conversation, "reality" means a believable, living world, but not necessarily our world. With that as my guide, I find that I must subject everything to a simple test:

"Can this illusion be faked through simpler means?"

I wonder if the exponential decay rate for memories gives us enough bang for the buck versus randomly pruning memories that don''t have an "eternal" flag. Maybe so. But for the moment, I''m not sure it changes the player''s experience enough to justify running those kinds of calculations in the background (for me, the newbie programmer).

I also like the circles of association. But again, until I learn C, or am running this on a P4 2000MHz, I wonder how many variables I can take into account? Currently, I want to get up to the point where, when two NPC''s meet, they do the following steps:

1. Will these NPC''s talk at all? Affected by:
- Differences in alignment
- Differences in class/profession
- A randomness factor
- (Eventually, when my agents have schedules, it will be affected by how busy they are, i.e., do they have time to talk)

2. Do the NPC 2 have knowledge available for NPC 1? Affected by:
- Simple check of what knowledge is exclusive.
- Removing knowledge that has special requirements (of class, profession, or other attributes - this will take a while to work out)
- Perhaps an intelligence/charisma differential to see how _much_ information can trade.

3. Transfer of knowledge.
- Initially, this will be random.
- At some point, knowledge will have a factor that makes it likely to spread faster.


If I can get those working, I think that''ll do most of the work of making such a system believable. The rest has to have a decent ratio of processing time versus added believability to make it worth my while, no? I do like the idea of adding a factor of threat or persuasion, and then various factors could effect that number.

Lastly, how the facts are generated. Consider a battle. There may be twenty people there. Certain facts about that battle are true - that it occured, that Joe the farmer died, that the orcs lost (another discussion here is what facts are _worth_ keeping up with, but we''ll just go with these for now).

There are a couple of ways of generating knowledge from this event. One is to have each person present "observe" the event in some way, possibly altering their perceptions based on their vantage point, skills of perception, stake in the event, and so on. This can be as simple or as complex as we like, but still must happen 19 times (one guy died, remember?). To me, it is much simpler to have the event itself (or actually several smaller events, as we''ll see) create a record of its relevent facts, then give those facts to all present.

For instance, when more than two people fight, I''ll call it a battle. Maybe we would want code to understand large versus small battles, and so on, but it''s a battle. So, there would be code to record the type of event ("battle"), the place, the time, and maybe how many people are present. When Joe the farmer dies, an "NPC death" event is kicked off. We would record a time, place, his name, and maybe a generic reference for those who know him less well ("a farmer," "a human scumbag," etc.).

A separate step would be to add those fact addresses to each person present. The only thing we really check for here is vicinity.

So, to me, that''s two steps per event, versus 19. And what if you have a battle with 500 people?

Just my thoughts. Thanks for reading these long-winded posts. Again, I''m having a great deal of fun, and would love to get to the point where I have something worth sharing. There is no one right way to do this, and I''m figuring it out for myself as I go along. I''d love to hear any other ideas, and of course anyone else''s ideas are as valid as mine.

- Gollum

PS - This issue of how involved to get with NPC''s makes me think there might be value to the idea of "generic NPC''s," who are needed to spread gossip, simulate an economy, fight in battles, and "super NPC''s," who are shopkeepers, thieves, office holders, bards, and so on. The super NPC''s would have the more complex code. Whaddaya think? Another thread?


It works.

I have a very basic implementation of my gossip system.

Several caveats are in order:
1. It''s in Python.

2. To RUN it, you''ll need python 2.2 (www.python.org), sdl 1.23 (www.libsdl.org), and pygame (www.pygame.org). However, they are cross-platform, take up very little space, and are very easy to install and use.

3. If you want to just read the python scripts, they''re ASCII text, and most decent C programmers should be able to decipher ''em with no problem. I comment a lot

4. Here''s all it does at the moment:
- Create 16 "facts," using all the permutations of four subjects and four predicates.
- Creates 2 NPC''s, and gives them 2 facts each.
- The NPC''s run around on a little tile-based map (yes, you can watch them, speed them up, slow them down, etc.)
- If they meet, the NPC''s trade one piece of data.
- After two meetings, they share the same knowledge base, and will declare such when they meet.

Not much, and the graphics aren''t great, but it is all I need for my basic gossip system. I can add other features, like NPC''s who are less likely to talk to each other because of alignment, etc, but at this point that would be pretty meaningless. Now, since that''s ALL I have, it''s time to work on my map editor, and learn about pathfinding. Then a basic combat system, so that they can kill each other, and spread the word about each others'' deaths.

Hee hee. I love getting stuff done.

Ok, the ace file lives here:
http://www.the-athenaeum.org/gossip.ace

I didn''t do a zip file because I couldn''t figure out how to get it to retain the folder structure.

Let''s keep talking about this, and I''ll keep working on it as well.

- Gollum
Couldn''t open your ace file:
! E:\something\gossip.ace: Unknown method in gossip\data\tileb_sand.gif

You were mentioning a simpler method?
This is what I would do

assign info priority levels to all of your entities.

Then ''spawn'' knowledge.
Knowledge would originally start off in the hands of only the most knowledgable people.
After X amount of time, it would be accessable to a class lower than that....
And again after X more time.
etc.
etc.

That way after the dragon is defeated, you could ''spawn'' the knowledge to another quest.
If the player got lucky they could learn about the quest right away, or if they went and did something else, eventually the quest would become so well known, even the drunk hobo can tell it to you!

Hmm. Cool idea. I had been thinking about the fact that some events would spawn knowledge instantly to certain people, no matter where they were. For instance, an NPC death would (for simplicity''s sake) be instantly known by the family. And maybe we would assume that wizards have powers of scrying that allow them to see things all over the place ...


I''ll try creating it as a zip file again; I just need to find a decent tutorial on making zip files that retain the folder structure. Also, I''ve moved on to some other tasks in my program, so it does a few other things, but the knowledge transfer code is still there, and well-commented.

I''ll post when I have the .zip file up.

- Gollum
Oh if your wondering, I haven''t found the option to retain folder structures in winzip... if thats what your using.
I use winrar or winace or something of that sort for zips...

yeah.
OFF TOPIC RESPONSE:

Later versions of WinZip provide a simple checkbox to maintain file structure... just make sure you use advanced mode rather than the Wizard. Fully functional trial versions of WinZip are available online. Check it out.

I installed Python to check out your app, but unfortunately I don''t have a decompression app suitable for whatever format it was you encoded it in.

Cheers,

Timkin
Reading about half way down I got an idea that would help with remembering old gossip.

Say after the npc talks to another npc about an old topic the decay counter would renew, and after the decay counter hits zero it doesnt mean he has forgot about it completely, for example, you remember past events from long ago but you might not remember it right away but maybe the following day. Well samething with the npc, he might forget about a topic but if the other npc brings it up then you could have a random number pick to see if he remembers it. say 1-50 the npc will remember while if that number is 51-100 then he doesnt remember. If he does remember then he could remember all the things about that topic and pass it on to another npc, if he doesnt then he wouldnt talk about it or forget out it all together.

Thats my idea, had to write it down before I forgot
Interested in being apart of a team of people that are developing a toolkit that can help anyone product an online game? Then click here http://tangle.thomson.id.au/
That''s basically the same idea as a decaying probability as I suggested earlier. Glad to see someone else thinks it is useful!

Cheers,

Timkin

This topic is closed to new replies.

Advertisement