Autoexit Changes - Version 2.0 - December 2003 ============================================== Introduction ============ This provides a number of changes to the default CircleMUD "autoexit" behaviour. It has been designed for the "suntzu" cwg distribution, and provides the following features: * Provide a new game play configuration option "display closed doors" to indicate whether closed doors are to be shown on the autoexit (and Exits) line; * Allow a new additional level of detail on the Autoexits command (similar to the "Exits") command showing the name of the room beyond the exit; * Provide a complete level of information to immortals. Making the Changes ================== 1. structs.h ------------ Add the following to the definition of the game_data struct: int disp_closed_doors; /* Display closed doors in autoexit? */ Also include the definition of a new preferance flag: #define PRF_FULL_EXIT 28 /* Shows full autoexit details */ /* Player autoexit levels: used as an index to exitlevels */ #define EXIT_OFF 0 /* Autoexit off */ #define EXIT_BASIC 1 /* Brief display (stock behaviour) */ #define EXIT_NA 2 /* Not implemented - do not use */ #define EXIT_FULL 3 /* Full display */ #define _exitlevel(ch) (!IS_NPC(ch) ? (PRF_FLAGGED((ch),PRF_AUTOEXIT) ? 1 : 0 ) + \ (PRF_FLAGGED((ch),PRF_FULL_EXIT) ? 2 : 0 ) : 0 ) #define EXIT_LEV(ch) (_exitlevel(ch)) The value of "28" above was chosen as the next value in the "PRF_" sequence. 2. utils.h ---------- Add the follong define in the Config macros section, to be used in cedit: #define CONFIG_DISP_CLOSED_DOORS config_info.play.disp_closed_doors 3. config.c ----------- Determine what you want as your default behavious - do you want closed doors automatically listed? Add the following at the end of the file, and set the value as required: /* * Do you want EXITS and AUTOEXIT to automatically display closed doors? * Set to NO to mimic historic behaviour - a player has to explicitly * look in a certain direction to see a door there. */ int display_closed_doors = YES; 4. interpreter.c ---------------- We need to add the definitions for the new autoexit command, so add the function template: ACMD(do_autoexit); With the other ACMD definitions, and add the command to the master command table: { "autoexit" , "autoex" , POS_DEAD , do_autoexit , 0, 0 }, 5. act.informative.c --------------------- This is where the bulk of the changes occur. Add the prototype definition of do_autoexit in the appropriate place, and add another paramater to the definition of do_auto_exits: ACMD(do_autoexit); void do_auto_exits(room_rnum target_room, struct char_data *ch, int exit_mode); "exit_mode" determines the verbosity of the output. Replace the original do_auto_exits with the following: void do_auto_exits(room_rnum target_room, struct char_data *ch, int exit_mode) { int door, door_found = 0, has_light = FALSE; if (exit_mode == EXIT_BASIC) { /* Standard behaviour - just list the available exit directions */ send_to_char(ch, "%s[ Exits: ", CCCYN(ch, C_NRM)); for (door = 0; door < NUM_OF_DIRS; door++) { if (!W_EXIT(target_room, door) || W_EXIT(target_room, door)->to_room == NOWHERE) continue; if (EXIT_FLAGGED(W_EXIT(target_room, door), EX_CLOSED) && !CONFIG_DISP_CLOSED_DOORS) continue; if (EXIT_FLAGGED(W_EXIT(target_room, door), EX_SECRET)) continue; if (EXIT_FLAGGED(W_EXIT(target_room, door), EX_CLOSED)) send_to_char(ch, "%s(%s)%s ", CCRED(ch, C_NRM), abbr_dirs[door], CCCYN(ch, C_NRM)); else send_to_char(ch, "%s ", abbr_dirs[door]); door_found++; } send_to_char(ch, "%s]%s\r\n", door_found ? "" : "None!", CCNRM(ch, C_NRM)); } if (exit_mode == EXIT_FULL) { send_to_char(ch, "%sObvious Exits:%s\r\n", CCCYN(ch, C_NRM), CCNRM(ch,C_NRM)); if (IS_AFFECTED(ch, AFF_BLIND)) { send_to_char(ch, "You can't see a damned thing, you're blind!\r\n"); return; } if (IS_DARK(IN_ROOM(ch)) && !CAN_SEE_IN_DARK(ch)) { send_to_char(ch, "It is pitch black...\r\n"); return; } /* Is the character using a working light source? */ if (GET_EQ(ch, WEAR_LIGHT)) if (GET_OBJ_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT) if (GET_OBJ_VAL(GET_EQ(ch, WEAR_LIGHT),2)) has_light = TRUE; for (door = 0; door < NUM_OF_DIRS; door++) { if (W_EXIT(target_room, door) && W_EXIT(target_room, door)->to_room != NOWHERE) { /* We have a door that leads somewhere */ if (GET_LEVEL(ch) >= LVL_IMMORT) { /* Immortals see everything */ door_found++; send_to_char(ch, "%-9s - [%5d] %s.\r\n", dirs[door], world[W_EXIT(target_room, door)->to_room].number, world[W_EXIT(target_room, door)->to_room].name); if (IS_SET(W_EXIT(target_room, door)->exit_info, EX_ISDOOR) || IS_SET(W_EXIT(target_room, door)->exit_info, EX_SECRET) ) { /* This exit has a door - tell all about it */ send_to_char(ch," The %s%s is %s %s%s.\r\n", IS_SET(W_EXIT(target_room, door)->exit_info, EX_SECRET) ? "secret " : "", (W_EXIT(target_room, door)->keyword && str_cmp(fname(W_EXIT(target_room, door)->keyword), "undefined")) ? fname(W_EXIT(target_room, door)->keyword) : "opening", IS_SET(W_EXIT(target_room, door)->exit_info, EX_CLOSED) ? "closed" : "open", IS_SET(W_EXIT(target_room, door)->exit_info, EX_LOCKED) ? "and locked" : "but unlocked", IS_SET(W_EXIT(target_room, door)->exit_info, EX_PICKPROOF) ? " (pickproof)" : ""); } } else { /* This is what mortal characters see */ if (!IS_SET(W_EXIT(target_room, door)->exit_info, EX_CLOSED)) { /* And the door is open */ door_found++; send_to_char(ch, "%-9s - %s\r\n", dirs[door], IS_DARK(W_EXIT(target_room, door)->to_room) && !CAN_SEE_IN_DARK(ch) && !has_light ? "Too dark to tell." : world[W_EXIT(target_room, door)->to_room].name); } else if (CONFIG_DISP_CLOSED_DOORS && !IS_SET(W_EXIT(target_room, door)->exit_info, EX_SECRET)) { /* But we tell them the door is closed */ door_found++; send_to_char(ch, "%-9s - The %s is closed.\r\n", dirs[door], (W_EXIT(target_room, door)->keyword) ? fname(W_EXIT(target_room,door)->keyword) : "opening" ); } } } } if (!door_found) send_to_char(ch, " None.\r\n"); } } Now replace the duplicated code in do_exits with the following: ACMD(do_exits) { /* Why duplicate code? */ do_auto_exits(IN_ROOM(ch), ch, EXIT_FULL); } Finally, add the do_autoexit command so players can set their autoexit level (the original "autoexit" was handled by do_gen_toggle) : const char *exitlevels[] = { "off", "basic", "n/a", "full", "\n"}; ACMD(do_autoexit) { char arg[MAX_INPUT_LENGTH]; int tp; if (IS_NPC(ch)) return; one_argument(argument, arg); if (!*arg) { send_to_char(ch, "Your current autoexit level is %s.\r\n", exitlevels[EXIT_LEV(ch)]); return; } if (((tp = search_block(arg, exitlevels, FALSE)) == -1)) { send_to_char(ch, "Usage: Autoexit { Off | Basic | Full }\r\n"); return; } switch (tp) { case EXIT_OFF: REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_AUTOEXIT); REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_FULL_EXIT); break; case EXIT_BASIC: SET_BIT_AR(PRF_FLAGS(ch), PRF_AUTOEXIT); REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_FULL_EXIT); break; case EXIT_FULL: SET_BIT_AR(PRF_FLAGS(ch), PRF_AUTOEXIT); SET_BIT_AR(PRF_FLAGS(ch), PRF_FULL_EXIT); break; } send_to_char(ch, "Your %sautoexit level%s is now %s.\r\n", CCRED(ch, C_SPR), CCNRM(ch, C_OFF), exitlevels[EXIT_LEV(ch)]); } Update the call to do_auto_exits in look_at_room: /* autoexits */ if (!IS_NPC(ch) && PRF_FLAGGED(ch, PRF_AUTOEXIT)) do_auto_exits(target_room, ch, EXIT_LEV(ch)); 6. db.c ------- Changes need to be made so the values set by cedit and saved in the configuration file will be restored. First, add a definition for the external variable: extern int display_closed_doors; In load_default_config, add the following line with the default settings: CONFIG_DISP_CLOSED_DOORS = display_closed_doors; In load_config, add the following "case 'd'" code: case 'd': if (!str_cmp(tag, "display_closed_doors")) CONFIG_DISP_CLOSED_DOORS = num; else if (!str_cmp(tag, "dts_are_dumps")) CONFIG_DTS_ARE_DUMPS = num; 7. cedit.c ---------- We need to make changes to allow cedit to set or clear teh display_closed_doors value. First, in cedit_setup, add the following line: OLC_CONFIG(d)->play.disp_closed_doors = CONFIG_DISP_CLOSED_DOORS; And in cedit_save_internally: CONFIG_DISP_CLOSED_DOORS = OLC_CONFIG(d)->play.disp_closed_doors; And in save_config: fprintf(fl, "* Should closed doors be shown on autoexit / exit?\n" "disp_closed_doors = %d\n\n", CONFIG_DISP_CLOSED_DOORS); The logical place to add these lines will be readily apparant. In cedit_disp_game_play_options, add a menu item for displaying closed doors: "%sP%s) Display Closed Doors : %s%s\r\n" "%sR%s) Mortals Level To Immortal : %s%s\r\n" You will notice the "Mortals to Level to Immortal" option has been shifted from P to R. Also include the fields to be displayed, adding the necessary line: grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.load_into_inventory), grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.track_through_doors), grn, nrm, cyn, CHECK_VAR(OLC_CONFIG(d)->play.disp_closed_doors), Finally, in cedit_parse, set the options in the CEDIT_GAME_OPTIONS_MENU case: case 'p': case 'P': TOGGLE_VAR(OLC_CONFIG(d)->play.disp_closed_doors); break; case 'r': case 'R': TOGGLE_VAR(OLC_CONFIG(d)->play.immort_level_ok); break; Recompile the program, and test. 8. lib/text/help/commands.hlp ----------------------------- You may also wish to update the help file: AUTOEXIT Usage: autoexit [{ off | basic | full }] Toggles the automatic display of currently available exits. Not all possible exits will be displayed, only those immediately available. If a door is closed it will not show up as a possible exit. In basic mode, available exit directions are listed in a single line, while in full mode, each available exit, and the room name the exit leads to, is shown on individual lines. Autoexit without a value shows your current autoexit level. See also: TOGGLE # Examples of Autoexits in Operation ================================== Lets look at in in operation, first for mortal characters. 1) Basic level autoexits ------------------------ We have set "display closed doors" to no. With autoexit level set to basic, this mimics stock behaviour: 93H 202M 93V > look The Dump The dump, where the people from the city drop their garbage. Through the garbage you can see a large junction of pipes, looks like the entrance to the sewer system. North of here you see the common square. [ Exits: n ] 93H 202M 99V > exits Obvious Exits: north - The Common Square 93H 202M 99V > open grate Okay. 93H 202M 99V > look The Dump The dump, where the people from the city drop their garbage. Through the garbage you can see a large junction of pipes, looks like the entrance to the sewer system. North of here you see the common square. [ Exits: n d ] 93H 202M 99V > exits Obvious Exits: north - The Common Square down - Too dark to tell. Now, the implementor used cedit to enable the display of closed doors. Lets try again; 93H 202M 99V > close grate Okay. 93H 202M 99V > look The Dump The dump, where the people from the city drop their garbage. Through the garbage you can see a large junction of pipes, looks like the entrance to the sewer system. North of here you see the common square. [ Exits: n (d) ] We can see the down exit is shown ni brackets, and coloured red (at least if this was a coloured document, (d) would be red). The exits command is more expressive: 93H 202M 99V > exits Obvious Exits: north - The Common Square down - The grate is closed. 2) Full Level Autoexits ----------------------- Now, we switch to full level autoexits. 93H 202M 99V > look The Dump The dump, where the people from the city drop their garbage. Through the garbage you can see a large junction of pipes, looks like the entrance to the sewer system. North of here you see the common square. Obvious Exits: north - The Common Square 93H 202M 99V > open grate Okay. 93H 202M 99V > look The Dump The dump, where the people from the city drop their garbage. Through the garbage you can see a large junction of pipes, looks like the entrance to the sewer system. North of here you see the common square. Obvious Exits: north - The Common Square down - Too dark to tell. 93H 202M 99V > exits Obvious Exits: north - The Common Square down - Too dark to tell. You can see the autoexit information is exactly the same as what exits would show us. Lets try somewhere where the light is better. 93H 202M 85V > look The Levee You are at the levee. South of here you see the river gently flowing west. The river bank is very low making it possible to enter the river. Obvious Exits: north - The Dark Alley At The Levee south - On The River A retired captain stands here, selling boats. Now, with display closed doors enabled once again, lets look: 93H 202M 85V > look The Levee You are at the levee. South of here you see the river gently flowing west. The river bank is very low making it possible to enter the river. Obvious Exits: north - The Dark Alley At The Levee east - The paling is closed. south - On The River A retired captain stands here, selling boats. This time, we see the exit listed. 3) Immortal Behaviour --------------------- With their autoexit level set to basic, immortals see much the same as mortal characters. We still haev display closed doors set to yes, and here is an example: 500H 100M 82V > look [ 3030] The Dump [ NO_MOB ] The dump, where the people from the city drop their garbage. Through the garbage you can see a large junction of pipes, looks like the entrance to the sewer system. North of here you see the common square. [ Exits: n (d) ] Notice how the closed down exit is indicated. "Exits", however, show us more: 500H 100M 82V > exits Obvious Exits: north - [ 3025] The Common Square. down - [ 7030] The Quadruple Junction Under The Dump. The grate is closed but unlocked (pickproof). Now, if we change the autoexit level to full, we see the complete exit details every time: [ 6659] Hay Loft [ DARK INDOORS ] Bales of hay and straw, various bags filled with chaff, oats and other feedstuffs, and old broken saddles and riding tack litter this area. Very little light from outside penetrates the solid walls and the dust from the hay and straw make seeing difficult. As you move, you kick up piles of dust making you cough and choke. Obvious Exits: south - [ 6658] Hay Loft. up - [ 6660] Hidden room. The secret trap is closed but unlocked. YOu can see this even works for exits flagged as secret.