Carefully. You need to bear in mind before doing this that simply
changing the max_level won't do it..you need to look at how levels affect
combat abilities, default mob values and all sorts of subtle facets of the
mud. After that, then:
1. In merc.h, change the value of MAX_LEVEL to what you want, and any
other defined level value that you need to alter.. eg if you will have 20
imm levels or whatever.
2. Grep your source for any occurrence of the old MAX_LEVEL value..there
are a few places this is hardcoded numerically.
3. In the command table in interp.c, look at the commands and see if your
imm structure now needs any of the levels changed for commands.
4. The fun part. In const.c, go through the skill_table, and change for
every skill the level at which every class now gets the skill/spell. You
may not need to do this for all cases, but take careful note of how skills
unavailable to a class are set to the lowest imm level..if you now have
more mortal levels than this all these values will need to be changed. If
you go over 100 levels, make sure to change the value of the 'reserved'
slot, as bad things can happen otherwise.
5. Do a clean compilation (delete all .o files and do 'make') and restart
the mud.
6. If all is well, this is the basics of adding more levels.. other points
you may have to address are:
- if keeping pfiles handling old imms..either advancing by hand, or
incrementing your pfile version and handling the change in save.c
. - changing area files, to change mobs stats, obj stats, and generally
trying to keep the area re-balanced. Refer to previous note on the combat
system.
The procedure for adding a new skill or spell is generally similar, in that you need to write the actual code that actually carries out the skill/spell in question and then also make appropriate definitions to other files so that the addition can be integrated into the existing system.
For skills:When input is received from the player, the mud starts at the top of the table and sees if what they have typed can be matched against any of the entries in the table. Thus if they typed 'exam fido', the mud would go through the table, comparing every entry against the word 'exam' either until a match is found, or until the entire table is searched. Two things are of note here. Firstly, for efficiency, the most commonly used commands are first in the list, which is why you see the movement commands before anything else. When adding a new command therefore, think carefully of how often it is used, and try to place it accordingly. You will notice the table is generally grouped into combat commands, informational commands and such, so finding an appropriate place isn't terribly difficult. The second consideration comes from the fact that the mud will allow you to type abbreviations for a command..thus 'n' executes the 'north' command, not 'notell'. Again this requires careful positioning of commands.. it's quite easy to place a command in the table only to realise you've made it so that a frequently used contraction now executes this command instead.
The ROM code as did Merc before it uses a convention whereby all functions
that are written to execute a player-typed command are named do_*, such as
do_say, do_kill or do_cast. It is important to keep this in mind, as more
importantly, all do_ functions must have the same signature, that
being
void do_*(CHAR_DATA *ch, char *argument) ;
You have an incorrect value for either MAX_CLASS, MAX_RACE, or MAX_CLAN in merc.h. If one of these values is larger than it should be, someone typing 'who jhhjhgk' will have the mud go searching into places it shouldn't go, with predictably dire results.
You haven't set the exp modifier for their class in the pc_race_table. Because this is declared as an array, forgetting to do it for a new class will effectively mean they need 0 xp per level. One kill therefore, will take them to the maximum level achievable by killing mobs.
If you are using the mobprogs by Newt, there is an error checking routine
that can sometimes cause all mobprogs to stop working until the next
reboot. In program_flow(), there is a variable used to detect the level
of call nesting of mobprogs, which is intended to stop mobprogs which call
each other in an infinite loop. This variable is increased once the
function is entered, and decreased at the end of the function, but the
problem lies in the routes taken through the function by a bad mobprog.
If the function detects a problem with the mobprog, and returns from it
without reaching the end, the variable isn't decremented, and once this
happens 5 times all mobprogs mud-wide cease being executed. If you see an
error in your log file of the format:
Mobprog: max_call_level exceeded
Then this is indicitive of this problem.
The solution is to go through the program_flow() function, and add a
call_level-- ;
Before anywhere where there is a 'return' statement. You probably want to
do this instead of just disabling the check as someone will build looping
mobprogs if you do.
You can't simply just start defining 'ff', 'gg' and so on. The flags in Rom are held in 32 bit variables, so trying to assign values larger than a 32 bit number can hold isn't going to work very well. Note that 64 bit machines may not suffer this limitation, it will depend on what the compiler allocates for the variables.
There are a number of solutions to the problem, ranging from redefinition as 'long long', restructuring the flag variables as bit arrays and the most common, which is to simply add a new field for the additional flags. In this way, you will have a new field in the appropriate structures for 'act2', 'affect2' or whichever you need. You will need to add new functions for setting and checking these new variables, but it is largely an exercise in copying what is already there. If you're careful you can add as many new fields as you need and keep it totally transparent to players, imms and builders alike. There is at least one snippet for this available, and searching the Rom archives should yield a few past discussions.
To stop players simply staying in an area and collecting vast amounts of loot through object resets, 'o' and 'p' resets will not function to the room if the area has any players in it. Thus, if a 'o' reset is set to load a pile of gold into a treasure room and a player picks it up, no matter how long the player waits in the area, area resets will not repop that object to the room. Once the player leaves the area, the object will repop on the next area reset. This check can be removed in the reset code in db.c if you feel it is sufficiently necessary.
Firstly, do you really need to? Rom as is gives you 32k vnums, and there are precious few muds with that many rooms, mobs or objects. If you do need this though, it will require a fair amount of code changing, all of which though is the simple act of changing the declaration of the 'vnum' field in the structures that have it to a 'long'. This will give you a few billion vnums. You will also need to change those functions that directly access vnums, as they may assign a vnum to a local variable whose type will also need changed.
After adding mobprogs, some people find that when switched into a mob they don't see a lot of the mud text, most notably communications channels. The cause of this is the code added to the 'act' function, to check for an ACT trigger on a mob. The code returns from the function if the mob doesn't have such a trigger, but doesn't take account for a switched imm. Add a clause to the 'if' check to return only if the mob has no descriptor and this problem should go away.
In short, you don't. The ANSi colour codes used to display colour on terminals specify only eight colours, with bold versions of each, and a number of other control sequences. You cannot simply add a bunch of new codes, the standard does not support it. You will even find massive variations in how different terminal programs handle the 'official' codes, so even by using these you are not guaranteed to have them display correctly on every users screen.
[by Gabrielle Taylor, blame her]
social.are is required, but you can edit the socials in it as you please. Certain help related areas (rom.are, help.are, group.are) should not be removed unless you're positive that you've copied out the helps required by license (help rom, help merc, help diku) and have your versions of help newbie and help greeting in another file. (There may be other helps automatically called by the code that I'm not sure of.)
limbo.are, midgaard.are, school.are, immort.are, air.are, and gangland.are all contain mobs, objects or rooms that the code calls. Also note that removing a single area may cause other areas to break. You may accidentally remove rooms, mobs or objects that are linked to, or reset in, other areas. Always do this on a backup.
The #defined names of all required objects, mobs or rooms are provided here for your convenience. They are all located in merc.h.
limbo.are is required for the creation of corpses, body parts, money, and some spell related objects. It also contains the rooms that link dead characters drift into.
Only edit or remove it if you're sure of what you're doing.
OBJ_VNUM_SILVER_ONE 1 OBJ_VNUM_GOLD_ONE 2 OBJ_VNUM_GOLD_SOME 3 OBJ_VNUM_SILVER_SOME 4 OBJ_VNUM_COINS 5 OBJ_VNUM_CORPSE_NPC 10 OBJ_VNUM_CORPSE_PC 11 OBJ_VNUM_SEVERED_HEAD 12 OBJ_VNUM_TORN_HEART 13 OBJ_VNUM_SLICED_ARM 14 OBJ_VNUM_SLICED_LEG 15 OBJ_VNUM_GUTS 16 OBJ_VNUM_BRAINS 17 OBJ_VNUM_MUSHROOM 20 (create food spell) OBJ_VNUM_LIGHT_BALL 21 (continual light spell) OBJ_VNUM_SPRING 22 (create spring spell) OBJ_VNUM_DISC 23 (floating disc spell) OBJ_VNUM_PORTAL 25 (portal and nexus spells) ROOM_VNUM_LIMBO 2 (where link dead characters go)
air.are is required for the create rose spell. It is safe to copy obj #1001 from air.are into limbo.are, change the vnum to any unused number between 25 and 99, and change this define in merc.h, should you wish to remove air.are. (Note that this will probably be done in a Rom release after June 19/98)
OBJ_VNUM_ROSE 1001midgaard.are is required for the newbie map, the donation pit, the recall room and the altar room. It is safe to either redefine these values to existing vnums in your world, or to slash midgaard.are down to only containing these vnums.
OBJ_VNUM_MAP 3162 (map of Thera) OBJ_VNUM_PIT 3010 (donation pit) MOB_VNUM_FIDO 3090 (used in save.c) ROOM_VNUM_TEMPLE 3001 (recall room for non-clan) ROOM_VNUM_ALTAR 3054 (recall room for Loners)
school.are is required for newbie items, gained on login or on executing the outfit command. It is safe to either redefine these vnums to existing vnums in your world, or to slash down school.are to only contain these.
OBJ_VNUM_SCHOOL_MACE 3700 OBJ_VNUM_SCHOOL_DAGGER 3701 OBJ_VNUM_SCHOOL_SWORD 3702 OBJ_VNUM_SCHOOL_SPEAR 3717 OBJ_VNUM_SCHOOL_STAFF 3718 OBJ_VNUM_SCHOOL_AXE 3719 OBJ_VNUM_SCHOOL_FLAIL 3720 OBJ_VNUM_SCHOOL_WHIP 3721 OBJ_VNUM_SCHOOL_POLEARM 3722 OBJ_VNUM_SCHOOL_VEST 3703 OBJ_VNUM_SCHOOL_SHIELD 3704 OBJ_VNUM_SCHOOL_BANNER 3716 ROOM_VNUM_SCHOOL 3700 (where newbies log in to)
immort.are is required for room 1200, which is where immortals are placed if they were in rooms that no longer exist. It is safe to either redefine these vnums to existing vnums in your world, or to slash down immort.are to only containing one room.
ROOM_VNUM_CHAT 1200
gangland.are contains mobs and one object that are called in spec_troll_member, spec_ogre_member and spec_minotaur in special.c. If you remove this area, be sure to disable, remove, or rewrite these specials.
MOB_VNUM_PATROLMAN 2106 GROUP_VNUM_TROLLS 2100 GROUP_VNUM_OGRES 2101 OBJ_VNUM_WHISTLE 2116
As you may see, the act flags and plr flags are both set and checked for in the act field of CHAR_DATA. This is not a bug, nor a problem. It is merely a case of efficiency, act flags are only ever used by mobs, and plr flags only by players, so you should *never* have a char who needs both set.
You should be careful though, because of this setup it is vital that you use an IS_NPC to check whether the char in question is a mob or a player before ever setting or checking an act bit.
This function is used to get a random number. The number generated will be between 0 and (2^arg) -1, where arg is the value passed to the function. Some examples follow.
All player files have a version number, and you can use this as a mechanism for safely extending the data structures that hold player information without having to delete all your player files.
The problem is this- if you add say a new stat called charisma, the obvious thing to do is to write it to the player files with the other stats, therefore the lines involving stats will then have 6 as opposed to 5 numeric values. You will also change the player loading routine to read 6 stat values from each player file. However, any players created before this change were saved with only 5 stats, and the new code will choke when trying to read that extra stat.
The solution is that when you make this kind of change or addition, to increment the version number stored in each player file and check for versions lower than this in your loading routines. In the above example, if your original version was 5, you would increment this so that all player files saved in the new way are given version 6. Additionally, in the loading routines, you would check for the player version. If it was 6 or greater, read in 6 stats. If 5 or lower, read in 5 stats and then set the new stat to some default value. When this player saves out again, their file will be in the new version.
Note that this principle can also be applied to areas. If you find yourself adding new fields that need saved in the area files, it can be at best time consuming to convert all existing areas to conform to this new format. The procedure is easier if you have an OLC, but still not precisely fun. If you give your areas a version number, then additions and changes can be made in the same way as above. It can lead to slightly ugly loading routines, with lots of 'if (pArea->version < 4)' and such, but it does make the extension easier and allows you to retain the ability to read in older areas.
When a player is connected, from being at the initial name prompt to being in the midst of combat, any input he sends must be processed, according to both what he typed and his character's status. The function nanny, in comm.c is vital to this process.
If the player is in the game, then the game simply needs to determine if what was typed was a valid command and if so execute it. If the player is either logging on or creating, then things aren't quite so straightforward. This is where nanny comes in.
Each character, or more accurately each connection from a player to the mud has a value, the connected state that indicates where in the creation/logging/playing process the player currently is. This is an element of the DESCRIPTOR_DATA structure. All the possible values for this are defined in merc.h, and the names are pretty self-explanatory. CON_PLAYING is for players fully in the game and playing normally, CON_GET_PASSWORD is for someone who is at the password prompt.
If a player is in a state other than CON_PLAYING, then nanny is called when the mud receives input from them, the arguments sent to it being the players descriptor and the text they have typed. Note that it is the descriptor and not the character itself which is sent as some of the possible states such as CON_GET_NAME get input from the player before the mud has loaded their character.
The heart of nanny is a large switch statement, which looks at the connected state of the descriptor and acts accordingly. Generally, this action will involve some validation of the input, some output to the player, and then the setting of the connected state to the next stage the player should progress to. For example, say a player has connected, and is at the name prompt. This means they have entered nanny with their connected state set to CON_GET_NAME. The branch of the switch statement in nanny for CON_GET_NAME will firstly try to load a player file of that name, and if it finds one, needs then to prompt the player for his password. So, nanny loads the player file, sets the connected state to CON_GET_OLD_PASSWORD and returns. When the player then types his password, they will be brought back into nanny, but this time enter the switch limb for the CON_GET_OLD_PASSWORD state, where passwords are checked.
If there was no player file of the name the player typed, then the mud must instead prompt the player if this is the name they want for a new char. The mud prints such a message to them, and sets their connected state to CON_CONFIRM_NEW_NAME. When the player types something else in this situation, they again are brought into nanny, and this time the code for the switch limb for CON_CONFIRM_NEW_NAME is executed.
The bottom line is that nanny handles the processing of your char through all the possible stages involved in both normal login and creation. If you look at any one stage and compare it to how that stage acts when you are logging on you should see the correlation. What can confuse some is that each stage can set the players connected state to a few different values depending on the input, and things can even get circular. Think of how creation works and this isn't all that surprising. If you mistype your password confirmation the mud has to backtrack to the start of the password entering process. If you choose to customise then you enter customisation, otherwise you skip that stage. At every stage the mud will check your input and inform you if it was invalid, and will then put you back through that stage.
There are two common reasons for wanting to add additional connected states. The first is simply if you are changing your creation or login process in a way that requires input not normally needed in stock Rom. To do this you need to define a new state in merc.h, and add a new limb to the switch statement in nanny. You will need to make sure that the stage before the new one sets the player's connected state to the new state so that the new stage is entered, and that you correctly pass the player to the proper stage depending on their input. Usually this will either be to display an error message and keep them at this stage if their input was invalid, or to do some processing of their input and pass them to the next stage.
The other situation for a new connected state is if you want the ability within the mud to prompt a player for input. Possibilities here are menu driven OLC or note systems, confirmation of irreversable commands such as pkillon or remort and such. The principle is the same though, you define the new state, and add to the switch in nanny. You will process their input, and then either return them to normal playing, send them to another additional connected state, or keep them at this state if the input was invalid.