MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | LPC Basics |
| 2 | Written by Descartes of Borg |
| 3 | first edition: 23 april 1993 |
| 4 | second edition: 16 june 1993 |
| 5 | |
| 6 | CHAPTER 2: The LPC Program |
| 7 | |
| 8 | 2.1 About programs |
| 9 | The title of this chapter of the textbook is actually poorly named, since |
| 10 | one does not write programs in LPC. An LPC coder instead writes *objects*. |
| 11 | What is the difference? Well, for our purposes now, the difference is |
| 12 | in the way the file is executed. When you "run" a program, execution |
| 13 | begins at a definite place in the program. In other words, there |
| 14 | is a place in all programs that is noted as the beginning where program |
| 15 | execution starts. In addition, programs have definite end points, |
| 16 | so that when execution reaches that point, the execution of the program |
| 17 | terminates. So, in short, execution of a program runs from a definite |
| 18 | beginning point through to a definite end point. This is not so with |
| 19 | LPC objects. |
| 20 | |
| 21 | With muds, LPC objects are simply distinct parts of the C program which |
| 22 | is running the game (the driver). In other words, execution of the mud |
| 23 | program begins and ends in the driver. But the driver in fact does |
| 24 | very little in the way of creating the world you know when you play |
| 25 | a mud. Instead, the driver relies heavily on the code created in LPC, |
| 26 | executing lines of the objects in the mud as needed. LPC objects thus |
| 27 | have no place that is necessarily the beginning point, nor do they |
| 28 | have a definite ending point. |
| 29 | |
| 30 | Like other programming languages, an LPC "program" may be made up of |
| 31 | one or more files. For an LPC object to get executed, it simple |
| 32 | needs to be loaded into the driver's memory. The driver will call lines |
| 33 | from the object as it needs according to a structure which will be |
| 34 | defined throughout this textbook. The important thing you need to |
| 35 | understand at this point is that there is no "beginning" to an LPC |
| 36 | object in terms of execution, and there is no "end". |
| 37 | |
| 38 | 2.2 Driver-mudlib interaction |
| 39 | As I have mentioned earlier, the driver is the C program that runs on |
| 40 | the host machine. It connects you into the game and processes LPC code. |
| 41 | Note that this is one theory of mud programming, and not necessarily |
| 42 | better than others. It could be that the entire game is written in C. |
| 43 | Such a game would be much faster, but it would be less flexible in |
| 44 | that wizards could not add things to the game while it was running. This |
| 45 | is the theory behind DikuMUDs. Instead, LPMUDs run on the theory that |
| 46 | the driver should in no define the nature of the game, that the nature |
| 47 | of the game is to be decided by the individuals involved, and that |
| 48 | you should be able to add to the game *as it is being played*. This |
| 49 | is why LPMUDs make use of the LPC programming language. It allows |
| 50 | you to define the nature of the game in LPC for the driver to read and |
| 51 | execute as needed. It is also a much simpler language to understand |
| 52 | than C, thus making the process of world creation open to a greater |
| 53 | number of people. |
| 54 | |
| 55 | Once you have written a file in LPC (assuming it is corrent LPC ), it justs |
| 56 | sits there on the host machine's hard drive until something in the game |
| 57 | makes reference to it. When something in the game finally does make |
| 58 | reference to the object, a copy of the file is loaded into memory and |
| 59 | a special *function* of that object is called in order to initialize |
| 60 | the values of the variables in the object. Now, do not be concerned |
| 61 | if that last sentence went right over your head, since someone brand |
| 62 | new to programming would not know what the hell a function or a variable |
| 63 | is. The important thing to understand right now is that a copy of the |
| 64 | object file is taken by the driver from the machine's hard drive and |
| 65 | stored into memory (since it is a copy, multiple versions of that |
| 66 | object may exist). You will later understand what a function is, what |
| 67 | a variable is, and exactly how it is something in the game made reference |
| 68 | to your object. |
| 69 | |
| 70 | 2.3 Loading an object into memory |
| 71 | Although there is no particular place in an object code that must exist |
| 72 | in order for the driver to begin executing it, there is a place for which |
| 73 | the driver will search in order to initialize the object. On compat |
| 74 | drivers, it is the function called reset(). On native muds it is the |
| 75 | function called create(). [ MorgenGrauen is native - Boing ] |
| 76 | |
| 77 | LPC objects are made up of variables (values which can change) and |
| 78 | functions which are used to manipulate those variables. Functions |
| 79 | manipulate variables through the use of LPC grammatical structures, |
| 80 | which include calling other functions, using externally defined |
| 81 | functions (efuns), and basic LPC expressions and flow control |
| 82 | mechanisms. |
| 83 | |
| 84 | Does that sound convoluted? First lets start with a variable. A |
| 85 | variable might be something like: level. It can "vary" from sitation |
| 86 | to situation in value, and different things use the value of the player's |
| 87 | level to make different things happen. For instance, if you are a |
| 88 | level 19 player, the value of the variable level will be 19. Now |
| 89 | if your mud is on the old LPMud 2.4.5 system where levels 1-19 are |
| 90 | players and 20+ are wizards, things can ask for your level value to |
| 91 | see if you can perform wizard type actions. Basically, each object |
| 92 | in LPC is a pile of variables with values which change over time. |
| 93 | Things happen to these objects based on what values its variables |
| 94 | hold. Often, then things that happen cause the variables to change. |
| 95 | |
| 96 | So, whenever an object in LPC is referenced by another object currently |
| 97 | in memory, the driver searches to see what places for values the |
| 98 | object has (but they have no values yet). Once that is done, the driver |
| 99 | calls a function in the object called reset() or create() (depending |
| 100 | on your driver) which will set up the starting values for the object's |
| 101 | variables. It is thus through *calls* to *functions* that variable |
| 102 | values get manipulated. |
| 103 | |
| 104 | But create() or reset() is NOT the starting place of LPC code, although |
| 105 | it is where most LPC code execution does begin. The fact is, those |
| 106 | functions need not exist. If your object does just fine with its |
| 107 | starting values all being NULL pointers (meaning, for our purposes |
| 108 | here, 0), then you do not need a create() or reset() function. Thus |
| 109 | the first bit of execution of the object's code may begin somewhere |
| 110 | completely different. |
| 111 | |
| 112 | Now we get to what this chapter is all about. The question: What |
| 113 | consists a complete LPC object? Well, an LPC object is simply |
| 114 | one or more functions grouped together manipulating 0 or more |
| 115 | variables. The order in which functions are placed in an object |
| 116 | relative to one another is irrelevant. In other words: |
| 117 | |
| 118 | ----- |
| 119 | void init() { add_action("smile", "smile"); } |
| 120 | |
| 121 | void create() { return; } |
| 122 | |
| 123 | int smile(string str) { return 0; } |
| 124 | ----- |
| 125 | |
| 126 | is exactly the same as: |
| 127 | |
| 128 | ----- |
| 129 | void create() { return; } |
| 130 | |
| 131 | int smile(string str) { return 0; } |
| 132 | |
| 133 | void init() { add_action("smile", "smile"); } |
| 134 | _____ |
| 135 | |
| 136 | Also important to note, the object containing only: |
| 137 | |
| 138 | ----- |
| 139 | void nonsense() {} |
| 140 | ----- |
| 141 | |
| 142 | is a valid, but trivial object, although it probably would not interact |
| 143 | properly with other objects on your mud since such an object has no |
| 144 | weight, is invisible, etc.. |
| 145 | |
| 146 | 2.4 Chapter summary |
| 147 | LPC code has no beginning point or ending point, since LPC code is used |
| 148 | to create objects to be used by the driver program rather than create |
| 149 | individual programs. LPC objects consist of one or more functions whose |
| 150 | order in the code is irrelevant, as well as of zero or more variables whose |
| 151 | values are manipulated inside those functions. LPC objects simply sit |
| 152 | on the host machine's hard driver until referenced by another object in |
| 153 | the game (in other words, they do not really exist). Once the object |
| 154 | is referenced, it is loaded into the machine's memory with empty |
| 155 | values for the variables. The function reset() in compat muds or |
| 156 | create() in native muds is called in that object if it exists to allow |
| 157 | the variables to take on initial values. Other functions in the object |
| 158 | are used by the driver and other objects in the game to allow interaction |
| 159 | among objects and the manipulation of the LPC variables. |
| 160 | |
| 161 | A note on reset() and create(): |
| 162 | create() is only used by muds in native mode (see the textbook Introduction |
| 163 | for more information on native mode vs. compat mode). It is only used |
| 164 | to initialize newly referenced objects. |
| 165 | |
| 166 | reset() is used by both muds in compat mode and native mode. In compat |
| 167 | mode, reset() performs two functions. First, it is used to initialize |
| 168 | newly referenced objects. In addition, however, compat mode muds use |
| 169 | reset() to "reset" the object. In other words, return it to its initial |
| 170 | state of affairs. This allows monsters to regenerate in a room and doors |
| 171 | to start back in the shut position, etc.. Native mode muds use reset() |
| 172 | to perform the second function (as its name implies). |
| 173 | |
| 174 | So there are two important things which happen in LP style muds which |
| 175 | cause the driver to make calls to functions in objects. The first is |
| 176 | the creation of the object. At this time, the driver calls a function |
| 177 | to initalize the values in the object. For compat mode muds, this |
| 178 | is performed by the function named reset() (with an argument of 0, |
| 179 | more on this later though). For muds running in native mode, this is |
| 180 | performed by the function create(). |
| 181 | |
| 182 | The second is the returning of the room to some base state of affairs. |
| 183 | This base set of affairs may or may not be different from the initial |
| 184 | state of affairs, and certainly you would not want to take up time |
| 185 | doing redundant things (like resetting variables that never change). |
| 186 | Compat mode muds nevertheless use the same function that was used to |
| 187 | create the object to reset it, that being reset(). Native mode muds, |
| 188 | who use create() to create the room, instead use reset() to reset it. |
| 189 | All is not lost in compat mode though, as there is a way to tell the |
| 190 | difference between creation and resetting. For reset purposes, the |
| 191 | driver passes either 1 or the reset number as an argument to reset() |
| 192 | in compat mode. Now this is meaningless to you now, but just keep in |
| 193 | mind that you can in fact tell the difference in compat mode. Also |
| 194 | keep in mind that the argment in the creation use of reset is 0 and |
| 195 | the argument in the reset use is a nonzero number. |