4.0 MOBProgs: ============= This section will walk you through the list of Mob_Programs and how you should write them (with several examples provided). In general, this section of the builder's docs gives your mobs some hint of a personality. Lets face it folks, with-out a personality the mobs would just wait around for someone to kill them. "OH Yay! How boring". SO BE CREATIVE! --Some Useful Background-- The backbone of the MOBprogram is called TRIGGERS. Basically, they are procedure calls placed in the mud code which provide the context for what is going on around the mobile. So, if something happens in the mobile's room and a trigger is activated, a list of commands is sent to the interpreter in the mobile's name, thus making her/it/him do an appropriate something. Knowing the appropriate response for every mobile to possibly trigger is not easy. So, the command list shouldn't be a rigid script, but rather it needs to be somehow unique for the mobile and the situation (i.e. try to make it particular to the theme of the area or even to the mob.) However, in order to know the situation, a mobile needs to know more about the trigger than it just happened. So, we include some variables as well to set the context appropriately and provide realism. DON'T WORRY! The implementers (IMPS) know that area builders are not all versed in coding. But the IMPS require you, as a builder, to have ideas and to keep your audience in mind. Remember, you are not making the mobs to entertain the Immortals (i.e. try to stay away from doing the same things over and over, because this can turn a really great area into a boring waste of memory that is hardly visited by the mortals). This background should have provided you with the understanding of what mob_programs do (from the 'why they are used' perspective). Now we move onto the "meat" of the section of the Mob_programs. How to use mob_programs and which mob_progs are currently availablefor use by you, the builder. _________FORMAT OF THE MOBPROGS WITHIN THE MOB FILE________ ==Where do the mob_progs go?== If you choose to use mobprogs you place them in your MOB file within your mob, usually right after the line about default position. But, before line indicating multiple attacks (although multiple attacks are optional, when used they must follow the Mob_progs). Followed by the switching information (which is also optional). The general format would look like the following: <----------They-GO-HERE-- | <--Must be included when a Mob_prog(s) is/are used ==What are MOBprograms ?== MOBprograms are a way to make your mobiles more interesting. In general, you could say they are a simple way to get the mobs to show some life, without you having to be a computer genius and going to the trouble of making special procedures (i.e. special procedures take a bit of extra effort to make, and unless someone has gone to great lengths to add many special procedures, most mobiles have no idea you are in the room with them and rarely listen to what you say). So here is your chance to go make a mob unique. Enter the MOBprograms :) The Basic Idea Thus, the basic idea: let mobiles react to a myriad of (or as many as possible) mud events/situations by having them perform a list of commands which you can tailor to the moment through a simple and unintimidating scheme usable by any creator. ______________________________________________________________________________ -------------------------Variables------------------------------- To make things come alive, variables are needed. These are represented in the MOBprograms by using a dollar sign convention as in the socials file. When the mud command is processed, these variables are expanded into the values shown below. NOTE: Usually, it is best to use the short descriptions of mobiles and the names of players when speaking to them, but if you are performing an action to someone, almost always you want the name. The title field for players is an extra that probably won't often be used. Without further hesitation... the variables: $i the first of the names of the mobile itself. $I the short description of the mobile itself. $n the name of whomever caused the trigger to happen. $N the name and title of whomever caused the trigger to happen. $t the name of a secondary character target (i.e. A smiles at B) $T the short description, or name and title of target (NPC vs. PC) $r the name of a random char in the room with the mobile (never == $i) $R the short description, or name and title of the random char $j he,she,it based on sex of $i. $e he,she,it based on sex of $n. $E he,she,it based on sex of $t. $J he,she,it based on sex of $r. $k him,her,it based on sex of $i. $m him,her,it based on sex of $n. $M him,her,it based on sex of $t. $K him,her,it based on sex of $r. $l his,hers,its based on sex of $i. $s his,hers,its based on sex of $n. $S his,hers,its based on sex of $t. $L his,hers,its based on sex of $r. $o the first of the names of the primary object (i.e. A drops B) $O the short description of the primary object $p the first of the names of the secondary object (i.e. A puts B in C) $P the short description of the secondary object $a a,an based on first character of $o $A a,an based on first character of $p REMEMBER: In if_checks, the accepted variables are the basic ones (i,n,t,r,o,p). If a variable is referenced that doesn't exist, then the value is simply left blank (i.e. referring to $o when the trigger is: A kisses B). The only problem with the variables is that the secondary object and the secondary target are passed by act() in the same location. This means that if you reference $t in an A puts B in C situation, the result will probably be a mud crash or some weird side effect. If $t is used in an if_check (i.e. if isnpc($t) in the above situation). The basic fix for this is to change everyone who calls the act() procedure to specify a secondary object and a secondary character. But that is a fairly trivial twiddle, so we left it the way it is so that, you aren't forced to make all those twiddles to use the MOBprograms. EXAMPLES OF THE USE OF SOME VARIABLES ARE INCLUDED IN THE MOB_PROGRAM EXAMPLES PROVIDED BELOW *************************************************************** * * * NOTE: The remainder of this document describes MOBprograms. * * * *************************************************************** ------------------------MOBprogram Syntax---------------------- The easiest way to understand any syntax is by going through an example step by step, so here goes. First, the notation that is used: 1. anything contained in braces {} is required, 2. anything in brackets [] is optional, 3. anything in quotes "" is a case insensitive literal (so ALWAYS have what is in the "" in the right place), 4. NL refers to a required new-line. General example: ">"{trigger_type}" "{argument_list}"~" NL {program_command_1} NL {program_command_2} NL {program_command_3} NL . . . {program_command_N} NL "~" NL An Explanation of these terms: A TRIGGER_TYPE is one of the available triggers (listed further on in this section). A PROGRAM_COMMAND can be a social, a skill, or any other legal mud command, or a control flow command ('if','or','else' statemants). The ARGUMENT_LIST depends upon the trigger (usually a number, word or group of words put together into a phrase), but it is always parsed (read) into the system as a character string. ----------------Associating MOB_programs With A Mobile----------------- This method involves a simple in-file approach (i.e. you write the mob_prog directly into your mob in your MOBfile). At the end of the mobile block (i.e. on the line following the 'typical position' / 'default position' / 'sex line'), attach as many MOBprogram blocks as you like (using the Mob_program syntax from above). When you have all the mob_programs you want, place a '|' (pipe) on the line immediately after the last mob_program. NOTE: - MAKE SURE THE '|' IS ON A LINE BY ITSELF AND THAT THERE ARE NO BLANK SPACES BEFORE OR AFTER IT. - Also, ONLY include the "|" on those mobs that actually have MOB_PROGs. - If either of these methods are not followed correctly the mud does strange things and may not boot, which will force us to hunt you down and beat you with a smelly old fish :P This simple example has enough to start on, and should be easily followed (if you don't understand what every line does DON'T PANIC. It will all be clear shortly). #3062 fido dog~ the beastly fido~ A beastly fido is mucking through the garbage looking for food here. ~ The fido is a small dog that has a foul smell and pieces of rotted meat hanging around his teeth. ~ 161 0 -200 S 0 20 10 1d6+4 1d4+0 0 25 8 8 1 >greet_prog 60~ if isgood($n) if rand(30) mpechoat $n $I wags $l tail at you. mpechoaround $n $I wags $l tail at $n. endif else growl $n endif | <==========Note the pipe :) ====== End of Example. --Explanation of the above example-- 1. The section between line with #3062 and 8 8 1 is called the mobile block and is covered elsewheres (in the the section on building mobiles). 2. >greet_prog 60~ This tells the mob that if it can see something enter the its room, do whatever follows 60 percent of the time. 3. if isgood($n) An 'if statement' is a system used to check a condition. In this case, the condition being checked is the alignment of the character ($n) which has triggered the program to activate. The character that activates this mob_prog can be one of the following an npc, pc or an Imm that enters the room. 4. if rand(30) In this case the 'if statement' is used within another 'if statement' (called a nested 'if statement'). As such it is good practice to indent these lines 3 to 5 spaces to make the readability of the mob_prog easier. Like all 'if statements' this is a system used to check a condition. This is used to generate a random number, and check if the number that is generated is less than or equal to what is in the (). If it is then the remainder of the first if statement is completed. However, should the numbers not match, then nothing happens. 5. mpechoat $n $I wags $l tail at you. mpechoaround $n $I wags $l tail at $n. These 2 lines are very similar in function. MPECHOAT - uses the Mob command form of 'echo' in conjunction with the 'at' command, to direct a message to only one character (usually the one who has triggered the mob_prog to activate). The character it is directed at is indicated by the variable that immediately follows (usually $n). ONLY THE PERSON THAT THE Mob ECHO IS DIRECTED 'AT' WILL BE ABLE TO SEE THE MESSAGE. MPECHOAROUND - uses the Mob command echo and directs a message to those in the room with the person (or around the person) who triggered the mob_prog. 6. endif This is ALWAYS used to indicate the closing of and 'if statement'. From this example it closes the first 'if statement' preceeding its use (the if rand(30) in this case). 7. else Used to indicate a choice from the conditions specified in an 'if statement'(i.e. the conditions set in the 'if statement have NOT been met and therefore, provides for the opening of an alternative course of action.). Since the endif on the line above this closes the if rand(30), this else statement reffers to the if good($n) line. This is only looked at by the mob when the character who activates this mob_prog is NOT good. In which case the mob uses the social growl combined with the variable $n to give the character (and anything else in the room) the impression that the mob is growling at him/her/it. 8. endif This endif is used to close the other 'if statement', the if good($n) statement. 9. The '|' (pipe) is used to indicate the ending of all mob_progs, so use it when you have included all the mob_progs you wish for a mob to have. Another way to do this is to use mob_programs which have been previously stored in a file. The following is an example of how the above Mob_program could have also been written in the Mob, if the necessary mob_program file were present. ---------------------MOBprogram Files----------------------- We often use this method because it is often useful to have the same MOBprograms affecting several different mobiles. Referencing MOBprograms stored in an external file is needed. Using the syntax from above, one can place the 'dummy line' in the mob file in place of the MOB_Program block(s). CircleMud 2.20 with these modifications expects these programs to be stored under the lib/world/prg directory. One possible 'dummy line' could be ">" "in_file_prog" {MOBprogram_filename} "~" NL Therefore, to reuse our fido example with this 'dummy line' in place of the greet_prog, we would have; #3062 fido dog~ the beastly fido~ A beastly fido is mucking through the garbage looking for food here. ~ The fido is a small dog that has a foul smell and pieces of rotted meat hanging around his teeth. ~ 161 0 -200 S 0 20 10 1d6+4 1d4+0 0 25 8 8 1 >in_file_prog greet.prg~ <=====Note the tilde (~) | <=====Note the Pipe (|) End of Example EXPLAINATION of the EXAMPLE: 1. As in the previous example, the section between line with #3062 and 8 8 1 is called the mobile block and is covered in another section (in the the section on building mobiles). 2. >in_file_prog greet.prg~ Causes the mob to make a call to the file specified. In a file you would have a list of mob_programs in which the syntax is exactly the same as it is for an in_file approach: i.e. you have a list of MOBprogram blocks, NOT including any 'dummy' in_file_prog lines (because this would make use of a function called recursion, and recursion was outlawed to keep things simple) followed by a line containing only the '|' (pipe) in the first space. _Note_: There are _No_ list of program_commands as well as _NO_ second tilde '~' appearing in the above example, they are in the referenced file. This is a convienient method since more than one mobile can use the same file and also one mobile can call more than one file. Files referenced using the 'dummy' in_file_prog line are placed in the MOB_program list at the point where the dummy line exists. KEEP IN MIND THAT You can have multiple '>in_file_prog' blocks in a mob, and you can MIX 'in_file_prog' with in_line MOB_Prog blocks. -----------------------------Trigger Types---------------------------------- $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $ $ $ KEEP IN MIND THAT ALL MOB_PROGS HAVE TWO (that is 2) TILDES '~' $ $ - ONE tilde '~' goes after the argument to end the first line. $ $ - The SECOND tilde '~' goes on a line BY ITSELF at the end of $ $ EACH MOB_PROG. $ $ - Remember this and your life will be much simplier, and we $ $ won't come after you for causing the MUD to hang. $ $ $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Here is a basic list of trigers that should hold for most of your needs. However, new triggers are fairly easy to add. trigger argument and what must happen to activate trigger ----------------------------------------------------------------------------- act_prog WORDLIST or P WORD_PHRASE to match from act() to mobile bribe_prog INTEGER amount of minimum gold amount given to mobile entry_prog PERCENT chance to check when mobile moves to a new room give_prog FULL OBJECT NAME or ALL to match when obj given to mobile greet_prog PERCENT chance to check if visible char enters mobile's room all_greet_prog PERCENT chance to check when any char enters mobile's room fight_prog PERCENT chance to check at fight_pulse if mobile is fighting hitprcnt_prog PERCENT lower than mobiles hit/max_hit if mobile is fighting death_prog PERCENT chance to check after mobile has been slain rand_prog PERCENT chance to check whenever a PC is in the mobiles zone speech_prog WORDLIST or P WORD_PHRASE to match in dialogue to mobile Their names, argument syntax's, and translation into simpler English are given below, along with a few examples to make things clearer. Syntax: in_file_prog The argument is a single word which calls the location of the stored file as referenced from the running directory (MOBProgs). NOTE: Dummy trigger. Not valid in any file, only for use in loading files from the method described in the example above. Syntax: act_prog [p] - The argument is a series of keywords separated by spaces (a phrase). As the syntax line indicates, the first word is the character 'p' by itself. This indicates that the rest of the word series (or argument) is considered to be a phrase, and the trigger is activated whenever the phrase (argument) contained in the act() message is SEEN by the mob. - If the 'p' is left out, the act_prog will then respond to a keyword and be triggered by that word. - Both the phrase and keywords are case insensitive. NOTE: This is the most general trigger. It can apply to almost every event which happens on the mud. Basically this will trigger on almost anything you'll ever want (and some things you won't as well). For example: MOBprogram: >act_prog p pokes you in the ribs.~ <---Note 1st tilde poke $n <--------what the mob will do in response ~ <---Note 2nd tilde This trigger will only be activated if the mobile receives a message in which the above five words (pokes you in the ribs.) are found in the exact order and spacing given. It will then return the poke, (i.e. it will poke the character ($n) that had triggered the Mob_prog to activate). * NOTE:* - The PERIOD IS NEEDED because the words must be found on their own. This eliminates confusion when the keyword is 'hi' and a message with the word 'this' is being checked. - Neither 'emote' nor 'say' can trigger and 'act_prog', so it can ONLY be triggered by socials. Syntax: speech_prog [p] The argument is the same as for an act_prog (i.e. a word or word phrase). This is only triggered when the keyword or phrase is contained in a message which has been 'said' by a PC in the same room as the mob. * The PC restriction is not necessary, but it makes infinite loops between two talking mobiles impossible. It also makes it impossible for two NPC's to stand and discuss the weather. For example >speech_prog p get lost~ <-------Note the tilde if name($n) == WAR MPGOTO 3001 else say As if! endif ~ <-----Note the tilde '~' If the mob can see the string "says, 'get lost'" it will check to see if the character ($n) saying the phrase is WAR (if name check). - If it is WAR then this mobile will use the mob_command goto and go to the temple of Midgaard (room #3001). - If the name does not equal WAR, then this mobile will say 'As if!'. Syntax: rand_prog Generates a random number (the argument) which is between 1 and 100 inclusive. This trigger is checked at each PULSE_MOBILE (not to be confused with the tick interval of roughly 70 seconds, which is different), and if the argument is greater than a percentage-roll the trigger is activated. For example: >rand_prog 3~ <---note the '~' spit $r ~ <---note the '~' This mob_prog is triggered if the percentage-roll is less then 3 (i.e. it is triggered 3% of the time) causing the mob to spit at another character in the room (the choice of the other player is random, an keep in mind the mob will not chose itself to be spit on). If it is not triggered, then the next mob_prog is considered. NOTE: - This will happen even if there is no PC in the room with the mob, but there must be players in the same area. - It is useful for giving mobiles a bit of a personality. For instance a janitor who stops to spit tobacco, or complain about the hours, or wonder why there are no woman janitors on muds, or a fido which barks or growls or pees on the curb is much more alive than one which just sits there scavenging. - This trigger will even be checked when the mobile is fighting, so can provide some confusion if you don't expect it (for instance an mpecho about a fido peeing on the curb can happen during a fight or even while the mobile is lying mortally wounded!) Syntax: fight_prog - The argument is a percentage like in rand_prog. - This trigger is checked at each PULSE_MOBILE only while the mob is in combat, and if the argument is greater than a percentage-roll the trigger is activated. For example: >fight_prog 3~ <---note the '~' spit ~ <---note the '~' This mob_prog is triggered if the percentage-roll is less then 3 (i.e. it is triggered 3% of the time) and ONLY if the mobile is fighting something. It then causes the mob spits. If it is not triggered, then the next fight_prog is considered. Useful for giving mobiles COMBAT attitude. It is checked every PULSE_VIOLENCE when the mobile is fighting. Uses include : - casting spells, - cursing at the opponent, or - whatever. NOTE: ONLY the first successful one will be processed to save time. Also, this means that the mobile will not get lucky and 1. curse, cast a fireball, and 2. spit on the player, cast another fireball in the same pulse. Syntax: hitprcnt_prog The argument is a percentage (i.e. the percent of hitpoints which the mobile has left) and is checked ONLY while the mobile is in COMBAT. For example: >hitprcnt_prog 50~ <----note the '~' cast 'heal' $I ~ <----note the '~' In this example, the hitprcnt mob_prog is triggered when this mob has 50% (or less) of its max_hitpoints. I say, "or less" because some people think it can only be triggered when the mobile has exactly the number corresponding to half its original max_hitpoints, which is INCORRECT. The following formula can be used as a guide to when this example will be triggered: present hitpoints <= ((max_hitpoints of mobile) * 50%) NOTE: Multiple hitprcnt_progs should be listed in increasing order of percent since a 40% will always be activated before a 20% and, only the first successful hitprcnt trigger is performed. So, ALWAYS list the lower percents first. This way they have a chance of actually occuring. Syntax: greet_prog - A percentage argument. - Checked whenever someone enters the room with the mobile, and ONLY if the mobile can see the person enter. SO MAKE SURE YOU CONSIDER THE ROOM FLAGS AND WHETHER YOU WANT THE MOBILE TO SEE PEOPLE SNEAKING OR INVISIBLE, etc.. For example: >greet_prog 90~ <---note the '~' shake $n ~ <---note the '~' This causes the mob to shake hands with 90% of the things that it can see enter the room. NOTE: This is a BAD way of doing this for at least two reasons: 1. It can cause the machine to lag (which no-one wants) 2. It creates spam. A better way to achieve the same outcome is to use the MPECHOAT command, which was used in a previous example in this section and is discussed again further on in this section of the docs. - Greet_progs are good to use for shopkeepers who you want to welcome customers, or for pseudo-aggressive mobiles which need to discriminate on who they attack. -** NOT TRIGGERED IF THE MOBILE IS FIGHTING **- Syntax: all_greet_prog Again a percentage argument. NOTE: Like greet_prog, but it can be triggered even if the mobile didn't see the arrival (i.e. sneak, invis, etc.). Most useful for faking teleport rooms (if your mobiles can transfer) or for impassable guardians. **NOTE: Is NOT activated if the mobile is fighting.** Syntax: entry_prog Again a percentage argument. NOTE: Works the OPPOSITE way of a greet_prog. Whenever the mobile itself enters a new room, this can be triggered (i.e. when a mob wanders around an area/zone). Useful for looking around, or waving or other things that real PCs do when they arrive at a crowded room. Can have a list of 'entry_prog's, but ONLY the first successful one of these is done so the mobile doesn't look stupid by repeating commands resulting from multiple MOBprograms. Example: >entry_prog 50~ stare ~ >entry_prog 50~ smile ~ You'll notice that EACH mob_prog has 2 '~'s. When the mob enters a room it will either stare or smile, depending on if the first entry_prog is triggered. Syntax: give_prog The argument is either the complete name of an object, or the word 'all'. An example of a complete name would be: "sword shiny magic" vs. "sword". The complete name is whatever appears on the line of the object section under the VNUM. This is triggered when something that is given to the mobile matches the word(s) of the argument. For example: >give_prog scroll recall~ <-----Note '~' if isnpc($n) MPJUNK recall else wave $n endif ~ <----Note '~' - This example shows the use of a few Mob_progs. The argument is "scroll recall". If the giver ($n) is an npc the scroll is junked (same effect as when a mortal sacs an object) and this 'give_prog' terminates.. If the giver is a Playing Character (PC), then the mob waves at the giver ending this 'give_prog'. NOTE: - This is best used for quests. - Since the first successful trigger is the only one of this type which is processed, having an "all" argument for a ' give_prog' at the end of the MOBprogram list is essentially a default response. Syntax: bribe_prog The argument is any positive integer number (greater then zero). This is because you CAN NOT give a negative amount of money, nor could you give an amount of zero to a mob and expect a result (duh!). This trigger is activated whenever money is given to the mobile. If the amount given equals or exceeds the number, then process the commands that follow. NOTE: An argument of '1' would act as a default response. If money is given to a mobile with this trigger type, instead of the cash being added to mob->gold, the mobile is instead given a pile of coins in the proper amount (i.e. the amount given is placed in the mobs inventory as a mound of coins). This way, the mobile can drop the coins or refer to the object by "amount" (short description:"%d gold coins") This has some drawbacks, but it lets the mobile do something with the bribe. NOTE: Having the mob drop the coins it is given and then get the dropped coins, turns the coins into cash. This can be done sneakily if a NPC-only "at" command exists. Syntax: death_prog The argument is a percent once again and is triggered upon the death of the mob. If the random percentage is less than the argument (NUMBER) the mobile performs the MOBprogram commands rather than the usual death_cry sequence. An example: >death_prog 50~ <---Note the '~' if isimmort($n) break else MPOLOAD 12105 <-----This is special and disccussed later MPECHO The Batman's cowl falls to the ground. endif ~ <---Note the '~' This 'death_prog' makes use of a few simple things: 1. death_prog 50~ - indicates a 50% chance that this death prog will occur. 2. if the character ($n) that kills this mob is an immortal (isimmort) the death_prog terminates. 3. If the character ($n) that kills the mob is NOT an immortal, the mob will use the Mob_Prog to load an object (MPOLOAD the vnum of the object is 12105), in this case the Batman's Cowl. 4. Through the use of the mob echo command the rooms occupants are informed that something has indeed occurred. 5. The if statement is ended. NOTE: This occurs before the corpse is made, so the commands can be considered the mobiles last gasp. In fact this mob_prog SHOULD BE the last thing the mobs tries to do. Uses for this type of mob_prog include (but are not limited to): - destroy the items it was holding, or create (load) some items or mobs, or cast a spell on the killer and or the room, or even goto a new location and die there NOTE: No text message is displayed to the room unless you provide some. YOU SHOULD ALWAYS INCORPORATE A MESSAGE INTO YOUR DEATH_PROGRAMS so the occupants, of the room that the mobile was in, know what has happened or is going to happen. The position of the mobile is set to STANDING, and so it can do all the normal commands, without worrying about being DEAD. However, even if the mobile restores itself to full Hitpoints, it WILL STILL die. Therefore, this is not a way to immortal mobiles. However, the last thing this mobile does could be to goto some vacant room, load a fresh version of itself, drop all its items, force the new mobile to get all the items and wear them, send the new mobile back to the character who killed it and force the new mobile to attack that character. Along with a text message which said the mobile restored itself, this might be a convincing effect. (Note that your kitten could turn into a dragon this way too). Of course this assumes that some NPC commands have been implemented. Syntax: MPDEATHBLOW ~ NOTE: It instantly kills the victim. This is good for making mobs have special attacks, you can make a mob look like it crushes amother mob. *** USE THIS VERY VERY VERY SPARINGLY! *** ________SOMETHING TO KEEP IN MIND_________ Note that the first successful bribe_prog, give_prog, hitprcnt_prog, death_prog, fight_prog, rand_prog and entry_prog is the only one which is executed. All the successful greet(_all)_progs, speech_progs, and act_progs will be done. This is the best arrangement we found for handling situations where you imported several MOBprogram files for a mobile. NOTE: - If you are going to write lots of little files and piece them together to create the effect you want, it is advisable to not mix things together all that much, otherwise you have to pay close attention to the order in which the programs are added to the link list. - Also, NO mob_programs will be successful when the mobile is CHARMED! For the simple reason that while charmed, the mob has no self violition and therefore, it should act like it has none. This is done to protect mobiles which are given special powers from being implemented or abused by a player. One bug we had in early testing was a player who charmed a mobile and then used its aggressive greet_prog to attack other players. ______________________________________________________________________________ ---------------------Control Flow Syntax----------------------- In place of any legal mud command in a MOBprogram, one can substitute a flow of control command. Here is the syntax for a flow of control command. "if" {if_check_1} "("{argument}")" [{operator} {value}] NL ["or" {if_check_2} "(" {argument} ")" [{operator} {value}] NL] this can continue down to N numbers of if_checks (i.e. if_check_N) [ {program_command_1} NL ] [ {program_command_2} NL ] . . . [ "break" NL ] . . . [ {program_command_N} NL ] [ "else" NL ] [ {program_command_1} NL ] [ {program_command_2} NL ] . . . [ "break" NL ] . . . [ {program_command_N} NL ] "endif" NL Basically, it is: an 'if' line, followed by zero or more 'or' lines, followed by zero or more legal mud commands, which may contain a 'break' line, possibly followed by an 'else' line , followed by zero or more legal mud commands, which may contain a 'break' line, followed by an 'endif' line. By now, you should already have an idea of how this works from the previous examples. We will review this in some detail none-the-less. --Explanations An IF_CHECK is a string which describes under what context to compare things (i.e. it is used to check something or some condition). The ARGUMENT is the reference point from which the Left Hand Side (LHS) of an expression comes. The OPERATOR indicates how the LHS and Right Hand Side (RHS) of an expression are going to be compared. The VALUE is the RHS of the expression to be compared by the operator to the LHS of the expression. The BREAK command bails out of the entire MOBprogram regardless of the level of 'if' nesting. If that looks confusing, hang in there. This next example should help :) Otherwise you'll probably have to ask someone to mail you another example, since examples are the best way we know to explain syntax. EXAMPLE: >act_prog p utters the words, 'seferlki'~ <---note the '~' if isimmort($n) <======================1st 'if' break else if rand(77) <======================2nd 'if' if isfight($i) <======================3rd 'if' if mexists(6607) >= 1 <======================4th 'if' yell Help me!!! my friend.... endif <=================================closes 4th 'if' endif <=================================closes 3rd 'if' endif <=================================closes 2nd 'if' endif <=================================closes 1st 'if' ~ <----------------------------------note the '~' First of all, by using the indentation method it becomes clear which pair of 'if' and 'endif' statements correspond. This example uses the mob_program act_prog. The argument for the act_prog is a phrase (indicated by the 'p'). -The first 'if' statement checks to see if the character ($n), trying to cast the spell, is immortal. If the character is, then this part 'break's and the rest of the lines are skipped over until the corresponding 'endif' statement is reached. -The second 'if' statement generates a random number and checks if the number generated is less than or equal to the number in the (). If it is then the next line is looked at. If generated is not, then the next lines are skipped over and the 'endif' statement is triggered and the mob_prog ends. -The third 'if' statement does a check to see if this mobile is fighting something (or more specifically, if something is fighting this mobile). If it is it continues. If not, the remainder is skipped and the mob_prog terminates. -The fourth 'if' statement makes a comparison. It is checking to see if a mob (with the vnum of 6607) exists, by using the operators '>' and '='. So, the LHS of the expression is stating what you want to check (i.e. if the mob exists with the vnum of 6607). While the RHS of the expression is setting a limit (i.e. one or more of this mob on the mud). The operators are setting the conditions in which the check would be true or false. If the mob with vnum 6607 does exist, this would be true and the 'yell' would be done. If the mob does not exist, then this would be false and the mob_prog would terminate. The things you can check in an 'if' statement are listed below. ifcheck argument? meaning ----------------------------------------------------------------------------- rand(num) Is a random percentage less than or equal to num isnpc($*) Is $* an NPC ispc($*) Is $* a PC isgood($*) Does $* have a good alignment isfight($*) Is $* fighting isimmort($*) Is the level of $* greater than max_mortal ischarmed($*) Is $* affected by charm isfollow($*) Is $* a follower with their master in the room isaffected($*) & integer Is ($*->affected_by & integer) true (person only) hitprcnt($*) == percent Is the hit/max_hit of $* equal to percent inroom($*) == integer Is the room of $* equal to integer (person only) sex($*) == integer Is the sex of $* equal to integer position($*) == integer Is the position of $* equal to an integer level($*) == integer Is the level of $* equal to an integer class($*) == integer Is the class of $* equal to an integer goldamt($*) == integer Does $* have a gold total equal to an integer objtype($*) == integer Is the type of $* equal to an integer (armor,boat,etc) objval#($*) == integer Is $*->value[#] equal to an integer (# from 0-3) number($*) == integer Is the vnum of $* equal to integer time(*) == integer Is the value of * equal to an integer (from 0-23) name($*) == string Is the name of $* equal to string mexists(vnum) & integer Is mob of vnum >, =, or < the integer oexists(vnum) & integer Is obj of vnum >, =, or < the integer (limited eq also) An example of 'mexists' and 'oexists' Supposed you have a mob (mob_A) that you want, as a mobprog to load a mob (mob_B) when mob_A is in battle. If the mob_B is only used as a helper, and not normally loaded, there should only be one of them, so you could do the following: NOTE: the loaded mob's names is giant, and its vnum is 1200 >fight_prog 100~ if mexists(1200) == 0 mpmload 1200 force giant follow $i force giant assist $i endif ~ example for oexists On the mobs death, you want it to load up an item 30% of time, but only if there are 1 or less of those items already in the game. (And don't load it if its an immortal or a mob who kills this monster) (Vnum of item is 1250) >death_prog 30~ if not isimmort($n) if ispc($n) if oexists(1250) <= 1 mpoload 1250 mpecho The giant Moth coughs up a gem as it dies! else mpecho The giant Moth coughs up some blood. endif endif endif ~ ----------------------------Operators----------------------------- Most of the basic numeric operators are legal and perform the same function as in C. Feel at ease, you DON'T have to know C to use these. The string operators are a bit more confusing, but we have seen most of them already in this section of the builder's docs. There are negative versions of some of the operators. These are not strictly needed, since the if/else construct of Control Flow commands can handle either case. Numeric Operators: == String Operators: == != != > / < !/ >= <= & | For strings, '==' and '!=' check for exact match between the two al# ($*) == integer Is $*->value[#] equal to integer (# from 0-3) number ($*) == integer Is the vnum of $* equal to integer name ($*) == string Is the name of $* equal to string You can use the 'NOT' operator as well. The syntax is simply: [IF ($*) == ] For example: >greet_prog 20~ OR >greet_prog 20~ if not isevil($n) if isevil($n) or not level($n)==30 endif ~ endif ~ 'NOT' can also be used with the "or" construction, i.e. >greet_prog 50~ if isevil($n) or not isaffected($n) & 128 cast 'aura blast' $n endif ~ This would cast aura blast 50% of time an evil person, or a person who did not have sanc on walked into the room (sancs affect number is 2^7, or 128 keep in mind that we would prefer you to use bitstrings for almost all occassions. But the bitvectors do still work). NOTE: Please send any that YOU would like added to builders@strangemud.org mailing list. ______________________________________________________________________________ ----------------MOBcommands Of Interest------------------- These are fairly basic things, most of them are wiz commands which have been changed to allow mobiles to perform the commands. If we find a problem of immortals abusing these powers on the mud we will either ditch the immortals, or add a check in all of commands to only let NPC's with null descriptors do the commands. (However, you lose a little debugging help that way). Here are the basic MOBcommands that we found to be enticing: MOBcommand argument_list MOBcommand argument_list ----------------------------------------------------------------------------- MPSTAT MPASOUND MPJUNK MPECHO MPMLOAD MPECHOAT MPOLOAD MPECHOAROUND MPKILL MPPURGE [argument] MPGOTO MPAT MPTRANSFER [location] MPFORCE Syntax: MPSTAT Shows the MOB_programs which are set on the mob of the given name or vnum and some basic stats for the mobile An example: mpstat satan Name: satan devil evil baal baalzebul lucipher. Vnum: 9003. Short description: Satan himself. Long description: Satan himself is standing here, ready to drag you down to hel l!!!!! Hp: 25581/25581. Mana: 5000/5000. Move: 5050/5050. Lv: 100. Class: 7. Align: -1000. AC: -264. Gold: 1000000. Exp: 15000000. >all_greet_prog 100 if isimmort($n) or isnpc($n) break else MPOLOAD 9000 close door east lock door east MPJUNK keymaster endif Syntax: MPASOUND Prints the text string to the rooms around the mobile in the same manner as a death cry. Be CAREFUL when using this command because if you have an exit to some other zone, the sounds will carry into the other zone and may lead to confusion. This is really useful for powerful and aggressive mobs, and is also nice for wandering minstrels or mobiles like that in concept. Example: >rand_prog 5~ MPAT 24911 MPECHO A naked babbling loony runs down the hall. ~ This means there is a 5% chance of this prog being triggered. When it is triggered the rooms around room # 24911 will see this message. Syntax: MPJUNK Destroys the object referred to in the mobiles inventory (similar to the sac command for players). It prints NO message to the world and you can do things like junk all.bread or junk all. An example: >act_prog p Your blood chills as you hear~ get all MPJUNK all ~ This has the same effect as making a mob a scavenger. This prog is triggered when someone in the mobiles room dies and this usual message is displayed. The mobile gets everything and sacs all that it has (this includes what the mobile may have equipped also). So be sure to specify what you want it to sacrifice. This is nice for having janitor mobiles clean out their inventory if they are carrying too much (have a MOBprogram trigger on the 'full inventory') Syntax: MPECHO MPECHOAT MPECHOAROUND Prints the text message to the room of the mobile. The three options let you tailor the message to goto victims or to do things sneaky like having a merchant do: mpat guard mpechoat guard rescue_please This coupled with an act_prog trigger is an affective way of quickly bringing life to a mob. An example: >act_prog p utters the words, 'seferlki'~ if isimmort($n) break else if rand(77) if isfight($i) if mexists(6607) >= 1 yell Help me!!! my friend.... MPECHO $I utters the words, 'umvuac x'fusurus' MPECHO A huge hole suddenly opens up in the ground. MPAT $n MPECHOAT $n Your vision clouds as you are sucked through MPAT $n MPECHOAT $n the hole in the ground. MPAT $n MPECHOAROUND $n $n is sucked through a hole in the ground. MPAT sarhon MPECHO A large hole in the ground opens up. MPTRANSFER $n sarhon MPAT sarhon MPECHOAT $n Sarhon pulls you up through a hole. MPAT sarhon MPECHOAROUND $n Sarhon digs his hands into the ground and MPAT sarhon MPECHOAROUND $n pulls $n up. endif endif endif endif This example builds on the example given for multiple 'if' statements earlier. It uses all 3 types of echo commands. - MPECHO lets every one in a room see the message. - MPECHOAT lets only the person specified by the variable ($n in this case) see the message, i.e. ONLY the character that triggered the Mob_prog can see this message. - MPECHOAROUND lets only the characters around the specified person ($n in this case) see the message (i.e. The character that triggered the mob_prog does NOT see this message). Using these echo commands with specific variables makes the mud more interesting and personal, for all who play here. Syntax: MPMLOAD MPOLOAD Loads the obj/mobile into the inven/room of the mobile. Even if the item is non-takable, the mobile will receive it in the inventory. This lets a mobile distribute a quest item or load a key or something. Syntax: MPKILL Lets a mobile kill a player without having to murder and be fifth level. Lots of MOBprograms end up with mpkill $n commands floating around. It works on both mobiles and players. Syntax: MPPURGE [argument] Destroys the argument from the room of the mobile. This is useful when you want PC's to do the fighting and not mobs they have charmed. For example: >fight_prog 35~ if isnpc($n) MPECHO $I summons his jackels to devour $n! MPPURGE endif ~ This is triggered only when the mobile is in combat and only if the character that has activated it is a NonPlayingCharacter (NPC). PLEASE USE AN ECHO OF SOME SORT SO THE CHARACTERS IN THE ROOM KNOW WHAT IS HAPPENING OR WHAT HAS HAPPENED. ** NOTE: - WITHOUT an argument the result is the cleansing of all NPC's and items from the room with the exception of the mobile itself. - However, MPPURGE $i will indeed purge the mobile. This MUST be the LAST command the mobile tries to do, otherwise the mud cant reference the acting mobile trying to do the commands and bad things happen. Syntax: MPGOTO Moves the mobile to a room, another mobile, or an object requested. It makes no message of its departure or of its entrance, so these must be supplied with mpecho commands if they are desired. Syntax: MPAT Performs the command at the designated location. Very useful for doing magic slight of hand tricks that leave players dumbfounded.. such as metamorphosing mobiles, or guard summoning, or corpse vanishing. For example: >rand_prog 15~ MPAT 3001 cast 'darkness' ~ This has the effect of casting darkness in the Temple of Midgaard (room #3001). THIS IS JUST AN EXAMPLE PLEASE DO NOT DO THIS!!!! Syntax: MPTRANSFER [dest] Sends the victim to the destination or to the room of the mobile as a default. if the victim is "all" then all the characters in the room of the mobile are transferred to the destination. Good for starting quests or things like that. There is no message given to the player that it has been transferred and the player doesn't do a look at the new room unless the mob forces them to. Immortals cannot be transferred. Example: >greet_prog 100~ MPTRANSFER $n 6621 MPECHOAT $n You feel water rush from your lungs as you are suddenly MPECHOAT $n thrown from a whirlpool. ~ This transfers the character that activates the mob_program from the mobile to another room (room #6621). It then lets the character know that it has been moved. Otherwise the character would not know until he/she/it looked around. SO ALWAYS USE AN ECHO COMMAND OF SOME SORT TO LET CHARACTERS KNOW WHAT IS GOING ON!! Syntax: MPFORCE Forces the victim to do the designated command. The victim is not told that they are forced, they just do the command so usually some mpecho message is nice. You can force players to remove belongings and give them to you, etc. The player sees the normal command messages (such as removing the item and giving it away in the above example). Again, if the victim is "all" then everyone in the mobiles room does the command. This DOES NOT WORK on immortals. _______________________________________________________________________________ ******************************************************************** ** ** ** CODER TALK ** ** Do not read unless you understand coding principles: ** ** ** ******************************************************************** There is only one way for the mud to associate the program with the mobile. The result is a link list of mob_programs which are attached to the mobile_prototype. This is done at boot time, and so only one copy is kept, regardless of how many instances of the mobile are running about. This also means that there is no dynamic way to edit or modify the MOBprograms. ----------------Adding New Triggers------------------ This section explains how to add new triggers. All you have to do is to follow these simple steps... 1. Add the appropriate #define XXXXX_PROG to structs.h 2. Write a trigger procedure at the end of mob_prog.c 3. Add the new case in *mprog_type_to_name(...) in mob_cmd.c 4. Add a new if statement in mprog_name_to_type(..) in db.c There you have it, a new trigger for your MOBProgram system. --------------Miscellaneous Information------------------ There is really no limit to the number of MOBprograms a given mobile can have. However, the length of a single command block is limited by the value of MAX_STRING_LENGTH. In my version it was around 4k, so that is probably about 100 lines. The indentation spaces shown in the example above are NOT required, but do make it easier to read (and debug) The MOBprogram stuff runs totally without anything in the mob_commands.c file, but letting mobiles be a bit more godlike has allowed us to do what we consider to be wonderful things. The replicant and restoration mobiles described above as well as some nifty mob helping mob interactions are an example. It IS possible to accidentally make mobiles which can trigger in loops. The result is usually a mud crash or major CPU dent. We don't know any way to prevent this from happening, other than careful coding and a restriction of mobile travel from zones of one creator to another (another good reason to not have charmed mobiles do anything). Tracking down the culprit mobile is not always easy. The only thing we have found which always works, is to add a log statement into the MOBprogram driver and fill some disk space until it becomes apparent what commands are repetitively issued. Also, most infinite loops are flukes where the situation just happens to be right and usually it never happens again. The list of variables and triggers and if_checks will grow continuously as our creators demand the ability to do certain things. If you have a request or if you have a new one, we don't mind hearing about them, and if you find bugs, we shall gladly attempt to squash them for you. As additions or fixes are made, the code will occasionally be redistributed. However, if you want a current version, please feel free to ask. When the code is redistributed, a file containing the change history from the original release will be provided (when possible) to allow you to patch in the changes with low grief. ______________________________________________________________________________ +++++++++++++++++++++++++ONE LAST EXAMPLE+++++++++++++++++++++++++++++ >act_prog p pokes you in the~ if isnpc($n) chuckle poke $n else if level($n) <= 5 or isgood($n) tell $n I would rather you didn't poke me. else if level($n)>15 scream say Ya know $n. I hate being poked!!! kill $n break endif slap $n shout MOMMY!!! $N is poking me. endif endif ~ OK.. time to translate.. the trigger will only happen when the mobile gets the message "... pokes you in the ..." If the offender (recall the $n and $N refer to the char who did the poking...) is an NPC, then the mobile merely chuckles and pokes back. If the offender was a PC then good and low level characters get a warning, high level chars get attacked, and midlevel chars get slapped and whined at. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Revision date: November '97 WAR ===============================================================================