chapter 8 "Understanding the Lib" One of the most common questions I get goes something like this: "I'd like to change combat so that it is turns-based, with actions. How would I do this?" Another example might be "I'm setting up a farming system, with livestock and stuff. What should I look at?" To me, the questions are the same. Translated into my language, this is the meaning: "I have great ideas that require advanced knowledge of the lib to implement. How do I do it?" I'm usually at a loss when I get one of these, because I want to set people straight, but I don't want to hurt their feelings, either. In the FAQ's, my response is something along the lines of: "If there's anything in the Creator's Manual you don't understand, you aren't ready to try this." I hate to say that, because I think it's probably discouraging to hear. After all, whatever the project, it is very likely doable. You can make an LP mud do pretty much anything you want...that's the beauty of the flexibility of LPC. However, as they say, with great power comes great responsibility, and in this case, it is your responsibility to understand the lib, if you want to make major changes to it. Let's take the example of farming. Section I: Verbs ---------------- It is critical to understand how verbs work in order to do anything in Dead Souls of an advanced nature. Verbs are basically commands that do something to your environment, something in your environment, your "body", or something in your inventory. For example, "who" is not a verb. It's a standard command, which doesn't act on any cloned items. All it does is communicate with the lib to query the list of users logged on, and displays it to you in a particular manner. Then there's something like "zap". That *is* a verb, and it takes cloned items as arguments. When you "zap orc" this has a special meaning to the parsing system. The parser is the part of the game driver that tries to interpret your input and attempts to do something useful with it. When the parser catches a verb at the beginning of your input, it gets to work on figuring out how the rest of the words in the input relate to that verb. This is done through "rules". You can take a look at /verbs/creators/zap.c for the specific rules in this case. If the word or words (for example "first orc", "orcs", "an orc") match one or more objects in the room, the parser then sends the arguments to the verb object. The verb object is the loaded code from /verbs/creators/zap.c in this case. Depending on how the verb is coded, your command line will succeed or fail. For your new farming system, you're going to need some new verbs, so the first thing you need to do is understand verbs. You're going to have to build new verbs like "plow", and "plant", and "harvest". Therefore, you'll need to go over the verb tutorial, which is at http://dead-souls.net/verbs.html Section II: Lib Event Objects ----------------------------- In the verb tutorial, you read that when a verb acts on an object, the parser requires that the object have a function that handles that verb. If a chair object lacks a function like direct_sit() or something similar, the parser will assume your sit verb doesn't apply to chairs, and the command line will fail with something like "You can't sit on the chair". It would be incredibly tedious to have to code a sit verb handler in every piece of furniture you create. Similarly, your farmer's field plow *could* have a plow verb handler coded in it, but it is much better to create a lib object that your plow will inherit. That way, other objects can inherit that functionality without having to reinvent the wheel, and plowing in general will be a uniform experience across the mud. For example, one of the first systems I made when I started my lib obsession was the inheritable flashlight system. The original Dead Souls lib had regular old torches you'd light with a match, but it seemed to me that not every Dead Souls mud would be Sword & Sandals style, and a modern illumination system should be available. So I set about making a "turn" verb, so that once I had flashlights, you could "turn on the flashlight". I then created the lib object /lib/events/turn.c (when referring to lib objects, I often use the macro name. In this case, if I'd said LIB_TURN, it would be the same thing as saying /lib/events/turn.c). The lib object doesn't really *do* much of anything. That object isn't really where you need to be checking for validity of commands. What that object does, almost *all* it does, is to have functions that correspond to the verb "turn". That's it. It's kind of like a socket for a plug. The verb is the plug and you're trying to use it on something. If that something has a socket that fits your plug, then it'll work. Lib event objects come in different flavors, and some really do perform a bunch of thinking. But for the most part, for simple verbs, all you need is a lib event object that says "yes, I understand that verb". LIB_TURN is inherited by LIB_FLASHLIGHT. That means that when you clone an object that inherits LIB_FLASHLIGHT, it contains all the functions of /lib/flashlight.c plus all the functions that LIB_FLASHLIGHT inherits from LIB_TURN. Because your flashlight inherits LIB_FLASHLIGHT, which inherits LIB_TURN, when you issue the command line "turn on flashlight", the parser checks with the flashlight to see if it knows what you're talking about, and gets a "yes, I know that verb" response. At that point the parser says "fine, here's the rest of what this player thinks he can do with you and the turn verb" and now it's up to LIB_FLASHLIGHT to figure out whether it has enough batteries, of the right kind, with sufficient charge, and so on. For your new farming system, you'll need to implement a similar scheme. Your "plow" and "hoe" verbs will need lib event objects that can be inherited by the cloned objects you want to plow and hoe with. In this case, LIB_FLASHLIGHT and the turn verb aren't the best models for your new plowing system. This is because your plow is something you plow *with*, as opposed to something that *is plowed*. To see how a plowing system might be implemented, take a look at the "dig" verb, LIB_DIGGING, and LIB_DIG_WITH. This is what a shovel would use, so that you can "dig in sand with the shovel". After studying the dig system, and lots of trial and error, you will hopefully eventually come up with a plow system that will let you "plow field with plow", for example. Section III: Daemons -------------------- So, now you've created a plow verb, and a plow lib event object, it works, and now you're happily plowing along. Let's say that the rooms field1.c and field2.c are plowable rooms. Presumably, you don't want people to be able to plow here all the time. The fields need time to do their thing, and constant plowing would slow down the growth of your tender young corn stalks. Normally, you might deal with this by having a local variable in the room, so that "harvest time is 50 hours, unless someone plows again, which makes it take longer", this sort of thing. Let's call that variable PlowedTimes. But, oh noes! The mud rebooted! Now all the rooms have reset, and the planting and plowing variables have reset! You might avoid this problem by just not rebooting, but even if you manage never ever to reboot your mud, the mud periodically does resets of unused objects, retiring them from memory and resetting their values to zero. You might avoid *that* problem by setting your fields to be "NoClean", to avoid resets, but this is very inelegant. Rather than ensuring the integrity of your game data, you're just crossing your fingers and hoping it doesn't go away. The solution is to use a daemon. A daemon is an object loaded into memory that acts like an arbiter of information. For example, STARGATE_D keeps track of where stargates are, and which gates are in what state, and which gates are connected to each other. It is important to have one location where this data can be accessed, because a new gate must be able to know what other valid gates there are, and it must be able to know what gates are idle and therefore accessible. STARGATE_D is a central repository of this data, and serves as a mediator for connection requests, keeping things working right. In this case, the daemon's job would be to keep track of which fields have been plowed, how many times, and how long it'll take to get to harvest time. Dead Souls daemons typically use object persistence files ( http://dead-souls.net/ds-admin-faq.html#80 ) to avoid losing information during object reloads or mud reboots. A FARMING_D is exactly what you need to keep track of and manage this kind of data. Section IV: Skills ------------------ To what extent should people be able to plow? How well should they do it? If you care enough about farming to have come this far, you've probably got ideas about what good plowing is and what criteria a player should have for extracting the most from their land. This is where skills can play an important role. What you have to understand about skills is that they are simply variables in a player's body. Skills don't have to be gained by joining a class, guild, or being member of a race. Adding a skill to a player is as simple as having an object do something like this: this_player()->SetSkill("scuba diving",1); And if just strapping on a scuba tank does it, then now that player has that skill. Now, *normally* players are granted skills through something more sensible than just picking up an object. It makes more sense to have skills granted when a player is taught something by an npc, or joins a guild, or whatever, which is why traditionally that's how it has worked. So let's say you have a Farmer's Guild, then. When you show up and sign the registry, some npc pops out, "teaches" you the farming skills you need (by simply adding the skills "farming" and "plowing" and "sowing" to the player) and now you have the skills. If you want, you can even create a Farmer class, like Fighters, but that's up to you and not in the scope of this chapter. This plowing skill is totally useless right now. It does nothing at all, because you haven't yet coded anything that makes use of it. This is the key concept of the skills system that you must understand. Just giving a player a skill does not mean that it has any use. For a skill to be useful, there must be lib verbs and/or objects that evaluate the skill and perform calculations based on it. It is therefore time to add these skill checks to the objects that need them. For example, suppose our farmer's plowing skill is at level 5. This doesn't mean he's a level 5 player necessarily, just that at plowing, his skill level is 5. You might have a function in your /verbs/items/plow.c verb that checks that skill, and determines how long the field will take to grow based on it. Perhaps for a level 5 plower, the field will be ready for harvest in 45 hours. Perhaps for a level 10 plower, it would be 35. You might have either the plow verb or the plow lib event object do something like: int PlowFunction(string field){ int skill_level = this_player()->GetSkillLevel("plowing"); if(skill_level) skill_level *= 2; else skill_level = 1; FARMING_D->eventModHarvestTime(field, skill_level); return 1; } It's a silly example, but you get the idea. The "plowing" skill is valuable because the lib uses it in some way to modify events the player performs. If the lib doesn't know about it, the skill has no value. In the case of, for example, "blade attack", the lib checks for this if you're wielding a sword and you're in combat. Based on how good you are at blade attack, combat.c will modify how much damage you inflict when you hit your opponent. Section V: Special Abilities ---------------------------- Perhaps "plant" and "sow" are verbs that should only be available to players with the skills "planting" and "sowing". Or, if farming isn't your thing and you want to enhance combat, you might want Fighters who are members of the Viking Guild to have a special ability called "massacre" that can do extra special damage. This is best done by simply creating the sow, plant, and/or massacre verbs, then coding the verbs to work only for those people you designate. If the player isn't a Fighter and a Viking, perhaps the massacre verb would return something like "You have no idea how to do that." and do no more. You are, of course, free to implement a Special Abilities System along the lines of the existing Dead Souls spell system. I encourage you to do so, if you're so inclined, and to share that code with me, if it works. But it isn't necessary. The existing verb system is plenty sophisticated enough to handle such special events. Section IV: Summary ------------------- At this point in my lib coder development, I have a hard time distinguishing what is easy and what is hard for new people. I have been surprised by people who take a long time to grasp simple concepts. I have been surprised by people who grasp complex concepts so quickly that I can't answer their questions. Where you stand in that continuum I can't say. What I can say is that if this chapter seems like it went mostly over your head, you shouldn't worry too much about it. It took me years of coding experience and months of obsessed lib analysis to reach my current level of understanding. You should not expect yourself to grok everything in this guidebook the first time around. As suggested in the previous chapters, it's best to start small, slow, and steady. As you build simple things, more complex things will make more sense, and you'll eventually reach the level of technical expertise you need. This chapter was not written to make you feel overwhelmed by what you don't know. It was written so that you understand what you're asking when you say "How do I revamp bodies and limbs so they have knees and elbows you can poke people with?" Once you understand the lib, it really really isn't that hard to do. But if you are a beginner, don't set yourself up for failure by taking a leap at a project you don't have the experience to tackle.