chapter 34 "QCS: Modification of NPC's" In the previous chapter we learned how to make a generic object. Now that we have it, what to do with it? It's important to keep in mind that the generic thing now in front of you isn't just a clone from a template file. If the command you used was "create npc cowboy", there is now a file (probably) called /realms/you/area/npc/cowboy.c that contains the code for the creature in front of you. However, this poor beast has the most uninteresting of features. It is in fact so boring that it responds only to its generic type. Such that "examine cowboy" or "kill tex" won't work. You'll need to "look at npc". Accordingly, any modification commands need to be made referring to the new thing with an it responds to, until such a time as you change the id to suit your tastes. Let's carry on with the example of our generic npc. To make a cowboy out of him, we can either change his name, or his id, or both. Let's start with his name: %^GREEN%^modify npc name cowboy%^RESET%^ This makes the SetKeyName() directive in cowboy.c use "cowboy" as its argument, effectively allowing you to address this npc as "cowboy" from now on. Now you can "look at cowboy" with some results. Obviously our NPC isn't *just* a cowboy. He's also a human, a dude, and his name is Tex. How do we make him respond to all of these nouns? %^GREEN%^modify cowboy id%^RESET%^ You'll notice there are no arguments following the word "id". Setting a thing's id is different from most other settings. If you'll think back to the LPC datatypes chapter of this manual (you did read the LPC chapters, didn't you?) you'll remember that some information about objects is in the form of strings ("cowboy"), some is in the form of integers (the cowboy's health points, for example) and some is in the form of arrays, which are a group of data points. In this example we want the cowboy's id to be an array, because of the many ways we might want to address him. Therefore, we want the SetId directive in his file to look like this: SetId( ({"human", "dude", "tex" }) ); You might think that QCS should be able to accept multiple values like this on a line, perhaps with "modify cowboy id human dude tex" as the command. But what if you want this npc to be a "Boy Named Sue"? How would you accommodate id's that contain spaces? In designing QCS, I considered having escape characters to allow for such things, but ultimately reasoned that this was just way too much mess. Instead, SetId, and other directives that take arrays as arguments, are handled by entering a query session. Below is an example of what it might look like. The example is necessarily messy because I am including both the queries and the responses. --------------------------------------------------- > %^GREEN%^modify npc name cowboy%^RESET%^ Indenting file... "/tmp/indent.1136206130.tmp.dat" 15 lines 420 bytes Exit from ed. > %^GREEN%^modify cowboy id%^RESET%^ This setting takes multiple values. If you have no more values to enter, then enter a dot on a blank line. To cancel, enter a single q on a blank line. You may now enter the next value. So far, it is blank. If you're done entering values, enter a dot on a blank line. %^GREEN%^dude%^RESET%^ You may now enter the next value. So far, we have: ({ "dude" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^human%^RESET%^ You may now enter the next value. So far, we have: ({ "dude", "human" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^tex%^RESET%^ You may now enter the next value. So far, we have: ({ "dude", "human", "tex" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^boy named sue%^RESET%^ You may now enter the next value. So far, we have: ({ "dude", "human", "tex", "boy named sue" }) If you're done entering values, enter a dot on a blank line. %^GREEN%^.%^RESET%^ Entries complete. Final array is: ({ "dude", "human", "tex", "boy named sue" }) Indenting file... "/tmp/indent.1136206156.tmp.dat" 19 lines 459 bytes Exit from ed. /open/1136206138: Ok /realms/cratylus/area/npc/cowboy: Ok SetId modification complete. > %^GREEN%^exa tex%^RESET%^ Other than being human, this npc is entirely unremarkable. The male human is in top condition. --------------------------------------------------- If you were now to examine Tex's code (with the command "about tex") you'd see that his SetId directive now looks like this: SetId( ({"dude", "human", "tex", "boy named sue"}) ); Other NPC features take arrays also. SetAdjectives is one. You might enter this (mud output omitted for clarity): %^GREEN%^modify tex adjectives%^RESET%^ %^GREEN%^dusty%^RESET%^ %^GREEN%^hardy%^RESET%^ %^GREEN%^.%^RESET%^ %^GREEN%^look at dusty cowboy%^RESET%^ There are two other directives that require queries. Things and NPC's can be looked at, but they can also be smelled and listened to, if you add SetSmell and SetListen. The syntax is: %^GREEN%^modify tex smell%^RESET%^ And you will then be asked a question about keys and mappings. Understanding mappings is important, but for now you just need to understand that you are being asked *two* separate questions: 1) What on the cowboy is being smelled/listened to? 2) What is the smell/sound? What this means is that your input will look something like this: %^GREEN%^modify tex smell%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex smells of sweat and manure. What happens is this: - You enter the modify command. - You enter the word "default" to indicate this is Tex's general smell. - You enter a dot to indicate that you are done specifying what part of Tex is being smelled. - You then specify the smell. This may seem odd until you realize you can also add smells/listens to parts of things. Not on NPC's, though. We'll look at this more closely in later chapters. For now, just use the syntax as shown above. For adding a listen to the cowboy, it works the same way: %^GREEN%^modify tex listen%^RESET%^ %^GREEN%^default%^RESET%^ %^GREEN%^.%^RESET%^ Tex seems to be humming a jaunty melody. Other features of an NPC do not take arrays, so one-line commands will do. For example: %^GREEN%^modify cowboy long This is a cowboy who calls himself Tex, but is in fact a Boy Named Sue.%^RESET%^ %^GREEN%^modify cowboy short a cowboy%^RESET%^ %^GREEN%^modify cowboy level 5%^RESET%^ %^GREEN%^modify cowboy class fighter%^RESET%^ %^GREEN%^modify tex currency gold 1%^RESET%^ %^GREEN%^modify tex currency silver 12%^RESET%^ %^GREEN%^modify tex skill bargaining 5%^RESET%^ %^GREEN%^modify tex skill projectile attack 7%^RESET%^ %^GREEN%^modify tex stat strength 33%^RESET%^ %^GREEN%^modify tex property nice guy 1%^RESET%^ %^GREEN%^modify tex healthpoints 150%^RESET%^ %^GREEN%^modify tex maxhealthpoints 170%^RESET%^ %^GREEN%^modify tex melee 0%^RESET%^ %^GREEN%^modify tex unique 1%^RESET%^ If you now issue the "about tex" command you will see that all the changes you made have been put into the file. You may have noticed the "melee" keyword. Dead Souls 2 NPC's come in various shapes and sizes, and some of them shouldn't wield weapons. A wolf with a battle axe would be a strange sight indeed. However, the default combat system makes unarmed creatures extremely vulnerable in combat. To make an NPC combat-capable without weapons, use the new SetMelee directive. SetMelee(1) makes the NPC capable of proper unarmed combat. SetMelee(0) makes the NPC a weak opponent if unarmed. NPC's will generally try to bite during unarmed combat. If this is beneath the capability or dignity of your NPC, you can prevent this with: %^GREEN%^modify tex canbite 0%^RESET%^ If your NPC should try to escape when the battle isn't going his way, the wimpy settings should do: %^GREEN%^modify tex wimpy 30%^RESET%^ %^GREEN%^modify tex wimpycommand climb ladder%^RESET%^ If you don't specify a wimpy command, Tex will leave the room through a random exit. In this case, when Tex's health is down to 30% and he is in combat, he will try to climb a ladder. Some NPC's are designed to travel about. To enable this feature, use the wanderspeed directive: %^GREEN%^modify tex wanderspeed 5%^RESET%^ If you want him to travel more quickly, use a lower number. By default, wandering NPC's only wander in rooms that have already been loaded into memory. They avoid loading rooms because loading a bunch of rooms that only the NPC will ever see is a waste of your mud's resources. However, if you *do* want your NPC to wander in an unrestricted manner, regardless of whether a room is loaded, use the permitload directive: %^GREEN%^modify tex permitload 1%^RESET%^ By default, NPC's stand up when they can. This is so that if they collapse during combat, they try to get back up once they are able to do so. If you prefer that your NPC maintain some other posture, you can set that posture, then disable autostanding like this: %^GREEN%^modify tex posture lying%^RESET%^ %^GREEN%^modify tex autostand 0%^RESET%^ If he's especially lazy, you can have him take a nap this way: %^GREEN%^modify tex sleeping 10%^RESET%^ Which will have him wake up after about a minute. However, note that if you've disabled autostanding, he will remain lying down after he wakes up. If the NPC should be hostile, that is, he should attack any creatures that it sees enter a room, SetEncounter should do it: %^GREEN%^modify tex encounter 100%^RESET%^ This means that if the creature it sees has a charisma score of less than 100 (which should pretty much be always true), Tex will try to kill it. You can do some fancy stuff with SetEncounter, such as only attacking orcs, or actually doing something friendly, but to do so you can't use QCS. Read the NPC and Sentients chapter in the Creator's Manual for details on how to code such stuff. If the NPC is a golem or other such non-biological creature, it may be useful to specify what they are made of. The SetComposition setting for a clay golem might look like this: %^GREEN%^modify golem composition clay%^RESET%^ If it happens to be a golem that does not believe in violence as a solution to problems, you can make refuse to hurt others with the following: %^GREEN%^modify golem pacifist 1%^RESET%^ Vendors: ------- Vendors are a special kind of NPC that can sell stuff. Along with the standard NPC settings, vendors have the following: SetStorageRoom specifies where the vendor's stock is stored. If a valid room is specified, anything in that room can be sold by the vendor. SetLocalCurrency specifies the type of currency, such as gold or silver, that the vendor accepts. SetMaxItems is the maximum number of items in the storeroom that the vendor is permitted to sell. SetVendorType specifies the kind of stuff the vendor can trade in. "all" allows him to buy and sell whatever. But if he is a weapon vendor, he can't trade in armor, etc. See /include/vendor_types.h for the available vendor types. To have a "multi-type" vendor, you'll have to code it by hand. The result of that looks something like this: SetVendorType( VT_TREASURE | VT_ARMOR | VT_HERBS ); Barkeeps: -------- Like vendors, barkeeps sell stuff, but they are limited to selling food and drink. Unlike vendors, barkeeps have no limitation on the amount of stuff they can sell. They also do not have a storeroom. The stuff they can sell is specified in their SetMenu directive, like this: %^GREEN%^clone woody%^RESET%^ You clone a generic barkeep (/realms/temujin/area/npc/woody.c). %^GREEN%^modify woody menu%^RESET%^ If you don't understand these questions, type the letter q on a blank line and hit enter. Please enter the first key element for this mapping: %^GREEN%^bourbon%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^whiskey%^RESET%^ Please enter the next key element, or enter a single dot to finish entering key elements. %^GREEN%^.%^RESET%^ Please enter the value for key ({ "bourbon", "whiskey" }): %^GREEN%^/domains/town/meals/bourbon%^RESET%^ Barkeeps also have the SetLocalCurrency directive to specify the currency they accept.