/*************************************************************************** * OasisOLC - olc.c * * * * Copyright 1996 Harvey Gilpin. * ***************************************************************************/ #define _OASIS_OLC_ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "interpreter.h" #include "comm.h" #include "utils.h" #include "db.h" #include "olc.h" #include "dg_olc.h" #include "screen.h" #include "handler.h" /* * External data structures. */ extern struct obj_data *obj_proto; extern struct char_data *mob_proto; extern struct index_data *mob_index; extern struct index_data *obj_index; extern struct room_data *world; extern int top_of_zone_table; extern struct social_messg *soc_mess_list; extern int top_of_socialt; extern int top_of_world; extern int rev_dir[]; extern const char *dirs[]; extern struct zone_data *zone_table; extern struct descriptor_data *descriptor_list; /* * External functions. */ extern int zedit_setup(struct descriptor_data *d, int room_num); extern int zedit_save_to_disk(int zone); extern int zedit_new_zone(struct char_data *ch, int new_zone); extern int medit_setup_new(struct descriptor_data *d); extern int medit_setup_existing(struct descriptor_data *d, int rmob_num); extern int medit_save_to_disk(int zone); extern int redit_setup_new(struct descriptor_data *d); extern int redit_setup_existing(struct descriptor_data *d, int rroom_num); extern void redit_save_internally(struct descriptor_data *d); extern int redit_save_to_disk(int zone); extern int oedit_setup_new(struct descriptor_data *d); extern int oedit_setup_existing(struct descriptor_data *d, int robj_num); extern int oedit_save_to_disk(int zone); extern int sedit_setup_new(struct descriptor_data *d); extern int sedit_setup_existing(struct descriptor_data *d, int robj_num); extern int sedit_save_to_disk(int zone); extern int real_shop(int vnum); extern int free_shop(struct shop_data *shop); extern int free_room(struct room_data *room); extern void medit_free_mobile(struct char_data *mob); extern void trigedit_setup_new(struct descriptor_data *d); extern void trigedit_setup_existing(struct descriptor_data *d, int rtrg_num); extern int real_trigger(int vnum); extern hedit_save_to_disk(void); extern free_help(struct help_index_element *help); int find_help_rnum(char *keyword); extern hedit_setup_new(struct descriptor_data *d, char *new_key); extern hedit_setup_existing(struct descriptor_data *d, int rnum); extern aedit_save_to_disk(struct descriptor_data *d); extern free_action(struct social_messg *action); extern int find_action(int cmd); /* * Internal function prototypes. */ int can_edit_zone(struct char_data *ch, int number); int real_zone(int number); void olc_saveinfo(struct char_data *ch); /* * Global string constants. */ const char *save_info_msg[8] = {"Rooms", "Objects", "Zone info", "Mobiles", "Shops", "Triggers", "Help", "Actions"}; /* * Internal data structures. */ struct olc_scmd_data { char *text; int con_type; }; struct olc_scmd_data olc_scmd_info[8] = { {"room", CON_REDIT}, {"object", CON_OEDIT}, {"room", CON_ZEDIT}, {"mobile", CON_MEDIT}, {"shop", CON_SEDIT}, {"trigger", CON_TRIGEDIT}, {"help", CON_HEDIT}, {"action", CON_AEDIT} }; /*------------------------------------------------------------*/ /* * Exported ACMD do_olc function. * * This function is the OLC interface. It deals with all the * generic OLC stuff, then passes control to the sub-olc sections. */ ACMD(do_olc) { int number = -1, save = 0, real_num; struct descriptor_data *d; /* * No screwing around as a mobile. */ if (IS_NPC(ch)) return; if (subcmd == SCMD_OLC_SAVEINFO) { olc_saveinfo(ch); return; } /* * Parse any arguments. */ two_arguments(argument, buf1, buf2); if (!*buf1) { /* No argument given. */ switch (subcmd) { case SCMD_OLC_ZEDIT: case SCMD_OLC_REDIT: number = world[IN_ROOM(ch)].number; break; case SCMD_OLC_TRIGEDIT: case SCMD_OLC_OEDIT: case SCMD_OLC_MEDIT: case SCMD_OLC_SEDIT: sprintf(buf, "Specify a %s VNUM to edit.\r\n", olc_scmd_info[subcmd].text); send_to_char(buf, ch); return; case SCMD_OLC_HEDIT: /* * Altered as a nitpick. Why waste a sprintf() call when you know * that it's going to be a help entry? TR 5-18-98 */ send_to_char("Specify a help entry to edit.\r\n", ch); return; case SCMD_OLC_AEDIT: send_to_char("Specify an action to edit.\r\n", ch); return; } } else if (!isdigit(*buf1)) { if (strn_cmp("save", buf1, 4) == 0) { if ((subcmd == SCMD_OLC_HEDIT) || (subcmd == SCMD_OLC_AEDIT)) { save = 1; number = 0; } else if (!*buf2) { send_to_char("Save which zone?\r\n", ch); return; } else { save = 1; number = atoi(buf2) * 100; } } else if ((subcmd == SCMD_OLC_HEDIT) || (subcmd == SCMD_OLC_AEDIT)) number = 0; else if (subcmd == SCMD_OLC_ZEDIT && GET_LEVEL(ch) >= LVL_IMMORT) { if ((strn_cmp("new", buf1, 3) == 0) && *buf2) zedit_new_zone(ch, atoi(buf2)); else send_to_char("Specify a new zone number.\r\n", ch); return; } else { send_to_char("Yikes! Stop that, someone will get hurt!\r\n", ch); return; } } /* * If a numeric argument was given, get it. */ if ((number == -1) && ((subcmd != SCMD_OLC_AEDIT) || (subcmd != SCMD_OLC_HEDIT))) number = atoi(buf1); /* * Check that whatever it is isn't already being edited. */ for (d = descriptor_list; d; d = d->next) if (d->connected == olc_scmd_info[subcmd].con_type) if (d->olc && OLC_NUM(d) == number) { if (subcmd == SCMD_OLC_HEDIT) sprintf(buf, "Help files are already being editted by %s.\r\n", (CAN_SEE(ch, d->character) ? GET_NAME(d->character) : "someone")); else if (subcmd == SCMD_OLC_AEDIT) sprintf(buf, "Actions are already being editted by %s.\r\n", (CAN_SEE(ch, d->character) ? GET_NAME(d->character) : "someone")); else sprintf(buf, "That %s is currently being edited by %s.\r\n", olc_scmd_info[subcmd].text, GET_NAME(d->character)); send_to_char(buf, ch); return; } d = ch->desc; /* * Give descriptor an OLC struct. */ CREATE(d->olc, struct olc_data, 1); /* * Find the zone (or help rnum). */ if (subcmd != SCMD_OLC_AEDIT) { if (subcmd == SCMD_OLC_HEDIT && !save) OLC_ZNUM(d) = find_help_rnum(buf1); else if ((OLC_ZNUM(d) = real_zone(number)) == -1) { send_to_char("Sorry, there is no zone for that number!\r\n", ch); free(d->olc); return; } } /* * Everyone but IMPLs can only edit zones they have been assigned. */ if (GET_LEVEL(ch) < LVL_IMMORT) { if (!can_edit_zone(ch, OLC_ZNUM(d)) && (subcmd != SCMD_OLC_AEDIT) && (subcmd != SCMD_OLC_HEDIT)) { send_to_char("You do not have permission to edit this zone.\r\n", ch); free(d->olc); return; } } if (save) { const char *type = NULL; switch (subcmd) { /* * Removed as a nitpick. Why do something if it's unnecessary? * (cases for AEDIT and HEDIT removed) */ case SCMD_OLC_AEDIT: type = "action"; break; case SCMD_OLC_HEDIT: type = "help"; break; case SCMD_OLC_REDIT: type = "room"; break; case SCMD_OLC_ZEDIT: type = "zone"; break; case SCMD_OLC_SEDIT: type = "shop"; break; case SCMD_OLC_MEDIT: type = "mobile"; break; case SCMD_OLC_OEDIT: type = "object"; break; } if (!type) { send_to_char("Oops, I forgot what you wanted to save.\r\n", ch); return; } if (subcmd == SCMD_OLC_HEDIT) { send_to_char("Saving all help entries.\r\n", ch); sprintf(buf, "OLC: %s saves help entries.", GET_NAME(ch)); mudlog(buf, NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE); } else if (subcmd == SCMD_OLC_AEDIT) { send_to_char("Saving all actions.\r\n", ch); sprintf(buf, "OLC: %s saves all actions.", GET_NAME(ch)); mudlog(buf, NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE); } else { sprintf(buf, "Saving all %ss in zone %d.\r\n", type, zone_table[OLC_ZNUM(d)].number); send_to_char(buf, ch); sprintf(buf, "OLC: %s saves %s info for zone %d.", GET_NAME(ch), type, zone_table[OLC_ZNUM(d)].number); mudlog(buf, CMP, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE); } switch (subcmd) { case SCMD_OLC_REDIT: redit_save_to_disk(OLC_ZNUM(d)); break; case SCMD_OLC_ZEDIT: zedit_save_to_disk(OLC_ZNUM(d)); break; case SCMD_OLC_OEDIT: oedit_save_to_disk(OLC_ZNUM(d)); break; case SCMD_OLC_MEDIT: medit_save_to_disk(OLC_ZNUM(d)); break; case SCMD_OLC_SEDIT: sedit_save_to_disk(OLC_ZNUM(d)); break; case SCMD_OLC_HEDIT: hedit_save_to_disk(); break; case SCMD_OLC_AEDIT: aedit_save_to_disk(d); break; } free(d->olc); return; } if (subcmd != SCMD_OLC_AEDIT) OLC_NUM(d) = number; else { OLC_NUM(d) = 0; OLC_STORAGE(d) = str_dup(buf1); for (OLC_ZNUM(d) = 0; (OLC_ZNUM(d) <= top_of_socialt); OLC_ZNUM(d)++) if (is_abbrev(OLC_STORAGE(d), soc_mess_list[OLC_ZNUM(d)].command)) break; if (OLC_ZNUM(d) > top_of_socialt) { if (find_command(OLC_STORAGE(d)) > NOTHING) { cleanup_olc(d, CLEANUP_ALL); send_to_char("That command already exists.\r\n", ch); return; } sprintf(buf, "Do you wish to add the '%s' action? ", OLC_STORAGE(d)); send_to_char(buf, ch); OLC_MODE(d) = AEDIT_CONFIRM_ADD; } else { sprintf(buf, "Do you wish to edit the '%s' action? ", soc_mess_list[OLC_ZNUM(d)].command); send_to_char(buf, ch); OLC_MODE(d) = AEDIT_CONFIRM_EDIT; } } /* * Steal player's descriptor start up subcommands. */ switch (subcmd) { case SCMD_OLC_TRIGEDIT: if ((real_num = real_trigger(number)) >= 0) trigedit_setup_existing(d, real_num); else trigedit_setup_new(d); STATE(d) = CON_TRIGEDIT; break; case SCMD_OLC_REDIT: if ((real_num = real_room(number)) >= 0) redit_setup_existing(d, real_num); else redit_setup_new(d); STATE(d) = CON_REDIT; break; case SCMD_OLC_ZEDIT: if ((real_num = real_room(number)) < 0) { send_to_char("That room does not exist.\r\n", ch); free(d->olc); return; } zedit_setup(d, real_num); STATE(d) = CON_ZEDIT; break; case SCMD_OLC_MEDIT: if ((real_num = real_mobile(number)) < 0) medit_setup_new(d); else medit_setup_existing(d, real_num); STATE(d) = CON_MEDIT; break; case SCMD_OLC_OEDIT: if ((real_num = real_object(number)) >= 0) oedit_setup_existing(d, real_num); else oedit_setup_new(d); STATE(d) = CON_OEDIT; break; case SCMD_OLC_SEDIT: if ((real_num = real_shop(number)) >= 0) sedit_setup_existing(d, real_num); else sedit_setup_new(d); STATE(d) = CON_SEDIT; break; case SCMD_OLC_HEDIT: if (OLC_ZNUM(d) < 0) hedit_setup_new(d, buf1); else hedit_setup_existing(d, OLC_ZNUM(d)); STATE(d) = CON_HEDIT; break; case SCMD_OLC_AEDIT: STATE(d) = CON_AEDIT; break; } act("$n starts using OLC.", TRUE, d->character, 0, 0, TO_ROOM); SET_BIT(PLR_FLAGS(ch), PLR_WRITING); } /*------------------------------------------------------------*\ Internal utilities \*------------------------------------------------------------*/ void olc_saveinfo(struct char_data *ch) { struct olc_save_info *entry; if (olc_save_list) send_to_char("The following OLC components need saving:-\r\n", ch); else send_to_char("The database is up to date.\r\n", ch); for (entry = olc_save_list; entry; entry = entry->next) { if ((int)entry->type == OLC_SAVE_HELP) sprintf(buf, " - Help Entries.\r\n"); else if ((int)entry->type == OLC_SAVE_ACTION) sprintf(buf, " - Actions.\r\n"); else sprintf(buf, " - %s for zone %d.\r\n", save_info_msg[(int)entry->type], entry->zone); send_to_char(buf, ch); } } int real_zone(int number) { int counter; for (counter = 0; counter <= top_of_zone_table; counter++) if ((number >= (zone_table[counter].number * 100)) && (number <= (zone_table[counter].top))) return counter; return -1; } /*------------------------------------------------------------*\ Exported utilities \*------------------------------------------------------------*/ /* * Add an entry to the 'to be saved' list. */ void olc_add_to_save_list(int zone, byte type) { struct olc_save_info *new; /* * Return if it's already in the list. */ for (new = olc_save_list; new; new = new->next) if ((new->zone == zone) && (new->type == type)) return; CREATE(new, struct olc_save_info, 1); new->zone = zone; new->type = type; new->next = olc_save_list; olc_save_list = new; } /* * Remove an entry from the 'to be saved' list. */ void olc_remove_from_save_list(int zone, byte type) { struct olc_save_info **entry; struct olc_save_info *temp; for (entry = &olc_save_list; *entry; entry = &(*entry)->next) if (((*entry)->zone == zone) && ((*entry)->type == type)) { temp = *entry; *entry = temp->next; free(temp); return; } } /* * Set the colour string pointers for that which this char will * see at color level NRM. Changing the entries here will change * the colour scheme throughout the OLC. */ void get_char_cols(struct char_data *ch) { nrm = CCNRM(ch, C_NRM); grn = CCGRN(ch, C_NRM); cyn = CCCYN(ch, C_NRM); yel = CCYEL(ch, C_NRM); } /* * This procedure removes the '\r\n' from a string so that it may be * saved to a file. Use it only on buffers, not on the original * strings. */ void strip_string(char *buffer) { register char *ptr, *str; ptr = buffer; str = ptr; while ((*str = *ptr)) { str++; ptr++; if (*ptr == '\r') ptr++; } } /* * This procdure frees up the strings and/or the structures * attatched to a descriptor, sets all flags back to how they * should be. */ void cleanup_olc(struct descriptor_data *d, byte cleanup_type) { if (d->olc) { /* * Check for storage. */ if (OLC_STORAGE(d)) free(OLC_STORAGE(d)); /* * Check for help. */ if (OLC_HELP(d)) { switch (cleanup_type) { case CLEANUP_ALL: free_help(OLC_HELP(d)); break; case CLEANUP_STRUCTS: free(OLC_HELP(d)); break; default: /* The caller has screwed up. */ break; } } /* * Check for a room. */ if (OLC_ROOM(d)) { /* * free_room doesn't perform sanity checks, must be careful here. */ switch (cleanup_type) { case CLEANUP_ALL: free_room(OLC_ROOM(d)); break; case CLEANUP_STRUCTS: free(OLC_ROOM(d)); break; default: /* The caller has screwed up. */ break; } } /* * Check for an object. */ if (OLC_OBJ(d)) /* * free_obj() makes sure strings aern't part of the prototype. */ free_obj(OLC_OBJ(d)); /* * Check for a mob. */ if (OLC_MOB(d)) /* * medit_free_mobile() makes sure strings are not in the prototype. */ medit_free_mobile(OLC_MOB(d)); /* * Check for a zone. */ if (OLC_ZONE(d)) { /* * cleanup_type is irrelevant here, free() everything. */ free(OLC_ZONE(d)->name); free(OLC_ZONE(d)->cmd); free(OLC_ZONE(d)); } /* * Check for a shop. */ if (OLC_SHOP(d)) { /* * free_shop doesn't perform sanity checks, we must be careful here. */ switch (cleanup_type) { case CLEANUP_ALL: free_shop(OLC_SHOP(d)); break; case CLEANUP_STRUCTS: free(OLC_SHOP(d)); break; default: /* The caller has screwed up. */ break; } } /*. Check for aedit stuff -- M. Scott */ if (OLC_ACTION(d)) { switch(cleanup_type) { case CLEANUP_ALL: free_action(OLC_ACTION(d)); break; case CLEANUP_STRUCTS: free(OLC_ACTION(d)); break; default: /* Caller has screwed up */ break; } } /* * Restore descriptor playing status. */ if (d->character) { REMOVE_BIT(PLR_FLAGS(d->character), PLR_WRITING); STATE(d) = CON_PLAYING; act("$n stops using OLC.", TRUE, d->character, 0, 0, TO_ROOM); } free(d->olc); } } /* Everything below this line is part of the OLC+ package specifically. */ /* Can they edit a zone? This takes a zone's rnum. * * Any reason to add a REAL/VIRTUAL setup? TR 5-20-98 */ int can_edit_zone(struct char_data *ch, int number) { if (GET_LEVEL(ch) >= LVL_IMMORT) return TRUE; if (GET_LEVEL(ch) < LVL_IMMORT) return FALSE; if (!is_name(GET_NAME(ch), zone_table[number].builders)) return FALSE; return TRUE; } /* This handy little function will give the zone number * * of any object, room, or mob. TR 5-18-98 */ #define ROOM 0 #define OBJECT 1 #define MOBILE 2 int zone_number(void *what, int type) { struct char_data *character; struct obj_data *object; struct room_data *room; int return_value; switch (type) { case ROOM: room = (struct room_data *)what; return_value = zone_table[real_zone(room->number)].number; break; case OBJECT: object = (struct obj_data *)what; return_value = (GET_OBJ_VNUM(object) / 100); break; case MOBILE: character = (struct char_data *)what; if (IS_NPC(character)) return_value = -1; /* This formula seems to work in all cases, although I * * know it wouldn't in the case of rooms. The documents * * state that the top_of_zone specifies the last ROOM, * * but not object. I think the default is (zone#*10)+99 */ else /* Doesn't this look like it wouldn't work? It seems * * that C has decided to simply truncate integers in * * lieu of rounding them... Is this machine specific? * * TR 5-20-98 */ return_value = (GET_MOB_VNUM(character) / 100); break; default: return_value = -1; break; } return return_value; } /* This little function has real potential. Give it * * a source room's rnum and a target room's rnum, and * * it will do a copy. Use it in your own commands. * * TR 5-20-98 */ void copy_room(int rnum_src, int rnum_targ) { if (world[rnum_src].name) world[rnum_targ].name = str_dup(world[rnum_src].name); if (world[rnum_src].description) world[rnum_targ].description = str_dup(world[rnum_src].description); world[rnum_targ].sector_type = world[rnum_src].sector_type; world[rnum_targ].room_flags = world[rnum_src].room_flags; /* Note: ex_descriptions are not being * * copied. I think it will stay that way. * * TR 5-20-98 */ return; } /* Same as copy_room, but with objects. No error checking. * * Should this be made an integer so a check can be made for * * success? TR 2-20-98 */ void copy_object(int rnum_src, int rnum_targ) { if (obj_proto[rnum_src].name) obj_proto[rnum_targ].name = str_dup(obj_proto[rnum_src].name); if (obj_proto[rnum_src].description) obj_proto[rnum_targ].description = str_dup(obj_proto[rnum_src].description); if (obj_proto[rnum_src].short_description) obj_proto[rnum_targ].short_description = str_dup(obj_proto[rnum_src].short_description); if (obj_proto[rnum_src].action_description) obj_proto[rnum_targ].action_description = str_dup(obj_proto[rnum_src].action_description); if (obj_proto[rnum_src].ex_description) obj_proto[rnum_targ].ex_description = obj_proto[rnum_src].ex_description; obj_proto[rnum_targ].obj_flags = obj_proto[rnum_src].obj_flags; obj_proto[rnum_targ].worn_on = obj_proto[rnum_src].worn_on; /* add more if you want... */ return; } /* * Command interface for: * Copying a room or object to another. * Attempt at ending the spaghetti: 5-20-98 */ #define COPY_FORMAT "Usage: copy { room | obj } <source> <target>\r\n" ACMD(do_copy) { char src_num[256], targ_num[256], type[256]; int vnum_targ = 0, rnum_targ = 0, vnum_src = 0, rnum_src = 0; int save_zone = 0, room_or_obj = -1; argument = two_arguments(argument, type, src_num); one_argument(argument, targ_num); /* Here are reasons to give up. I think they're all right here. */ if (!*type || !*src_num) { send_to_char(COPY_FORMAT, ch); return; } else if (!*targ_num && (room_or_obj == OBJECT)) { send_to_char("You must specify a target when copying objects.\r\n", ch); return; } if (is_abbrev(type, "room") && is_number(src_num)) { room_or_obj = ROOM; vnum_src = atoi(src_num); rnum_src = real_room(vnum_src); if (!*targ_num) { vnum_targ = world[IN_ROOM(ch)].number; rnum_targ = IN_ROOM(ch); } else { if (!is_number(targ_num)) { send_to_char(COPY_FORMAT, ch); return; } vnum_targ = atoi(targ_num); rnum_targ = real_room(vnum_targ); } save_zone = zone_number(&world[rnum_targ], ROOM); } else if (is_abbrev(type, "obj") && *targ_num && is_number(src_num) && is_number(targ_num)) { room_or_obj = OBJECT; vnum_src = atoi(src_num); rnum_src = real_object(vnum_src); vnum_targ = atoi(targ_num); rnum_targ = real_object(vnum_targ); save_zone = zone_number(&obj_index[rnum_targ], OBJECT); } else { send_to_char(COPY_FORMAT, ch); return; } if ((rnum_src < 0) || (rnum_targ < 0)) { sprintf(buf, "The source and target %ss must both currently exist.\r\n", (room_or_obj == OBJECT ? "object" : "room")); send_to_char(buf, ch); return; } else if (!can_edit_zone(ch, real_zone(save_zone*100))) { send_to_char("You cannot edit that zone.\r\n", ch); return; } /* We should now be ready to go. All errors have been trapped (?) * * and we know what to do. TR 5-21-98 */ switch (room_or_obj) { case ROOM: copy_room(rnum_src, rnum_targ); break; case OBJECT: copy_object(rnum_src, rnum_targ); break; default: mudlog("SYSERR: OLC: Reached default case in do_copy!", NRM, MAX(LVL_IMMORT, GET_INVIS_LEV(ch)), TRUE); send_to_char("There was an error in your copy. Please report to an " "administrator.\r\n", ch); return; } /* I cheated right here a little bit. By coincidence, * * ROOM == OLC_SAVE_ROOM, and OBJECT = OLC_SAVE_OBJ. * * I think this is a Good Thing(tm), although if you * * change the OLC_SAVE_x defines, it will blow up. :P * * TR 5-21-98 */ sprintf(buf, "You copy %s %d to %d.\r\n", (room_or_obj == ROOM ? "room" : "object"), vnum_src, vnum_targ); send_to_char(buf, ch); olc_add_to_save_list(save_zone, room_or_obj); } /* Supporting functions for RLINK. A few of these are right out of * * OBuild, but I can't remember which. :P Credits to Samedi, and * * Daniel Burke, I believe. TR 5-21-98 */ /* Create an exit in a room (rnum) in this direction. (No target) */ int create_dir(int room, int dir) { if ((room > top_of_world) || (room < 0)) { log("create_dir(): tried to create invalid door"); return FALSE; } if (world[room].dir_option[dir]) return FALSE; CREATE(world[room].dir_option[dir], struct room_direction_data, 1); world[room].dir_option[dir]->to_room = NOWHERE; world[room].dir_option[dir]->exit_info = 0; world[room].dir_option[dir]->general_description = str_dup("You see nothing special.\r\n"); world[room].dir_option[dir]->keyword = NULL; world[room].dir_option[dir]->key = -1; return TRUE; } /* Remove an exit from a room (rnum). */ int free_dir(int room, int dir) { if ((room > top_of_world) || (room < 0)) { log("free_dir(): tried to free invalid door"); return FALSE; } if ((dir < 0) || (dir >= NUM_OF_DIRS)) { log("free_dir(): tried to free invalid door"); return FALSE; } if (!world[room].dir_option[dir]) return FALSE; world[room].dir_option[dir]->to_room = NOWHERE; world[room].dir_option[dir]->exit_info = 0; if (world[room].dir_option[dir]->general_description) free(world[room].dir_option[dir]->general_description); if (world[room].dir_option[dir]->keyword) free(world[room].dir_option[dir]->keyword); world[room].dir_option[dir]->key = -1; free(world[room].dir_option[dir]); world[room].dir_option[dir] = NULL; return TRUE; } /* These defines were harvested from.... zedit.c ? */ #define ZCMD (zone_table[zone].cmd[cmd_no]) #define W_EXIT(room, num) (world[(room)].dir_option[(num)]) /* ***************************************************** */ #define RLINK_FORMAT "Usage: rlink <dir> <connect|disconnect> <1|2> [target]\r\n" /* The big baby. */ ACMD(do_rlink) { char direction[10], command[20], type[10], target[10]; int vnum_base = 0, vnum_targ = 0, rnum_base = 0, rnum_targ = 0; int dir = 0, k = 0, type_int = 0, top_room = 0; int save_zone_1 = 0, save_zone_2 = 0, create_new_room = FALSE; argument = two_arguments(argument, direction, command); two_arguments(argument, type, target); if (!*direction || !*command || !*type) { send_to_char(RLINK_FORMAT, ch); return; } else if (!is_number(type)) { send_to_char(RLINK_FORMAT, ch); return; } type_int = atoi(type); if (type_int != 1 && type_int != 2) { send_to_char(RLINK_FORMAT, ch); return; } vnum_base = world[IN_ROOM(ch)].number; rnum_base = IN_ROOM(ch); if (!*target && !is_abbrev(command, "disconnect")) { create_new_room = TRUE; } else { if (!is_number(target)) { send_to_char(RLINK_FORMAT, ch); return; } vnum_targ = atoi(target); rnum_targ = real_room(vnum_targ); } if (rnum_targ < 0) { send_to_char(RLINK_FORMAT, ch); return; } save_zone_1 = zone_number(&world[IN_ROOM(ch)], ROOM); if (!can_edit_zone(ch, real_zone(save_zone_1*100))) { send_to_char("You cannot create exits in this zone.\r\n", ch); return; } if (!create_new_room) { if (rnum_targ < 0) { send_to_char(RLINK_FORMAT, ch); return; } save_zone_2 = zone_number(&world[rnum_targ], ROOM); } else { top_room = (zone_table[real_zone(world[IN_ROOM(ch)].number)].top); for (k = (save_zone_1 * 100); k <= top_room; k++) { if (k > top_room) { send_to_char("Cannot create a new room in this zone!\r\n", ch); return; } if (real_room(k) < 0) { CREATE(ch->desc->olc, struct olc_data, 1); CREATE(OLC_ROOM(ch->desc), struct room_data, 1); OLC_ZNUM(ch->desc) = world[ch->in_room].zone; OLC_NUM(ch->desc) = k; OLC_ROOM(ch->desc)->number = k; OLC_ROOM(ch->desc)->zone = world[ch->in_room].zone; OLC_ROOM(ch->desc)->name = str_dup("An unfinished room"); OLC_ROOM(ch->desc)->description = str_dup("You are in an unfinished room.\r\n"); OLC_ITEM_TYPE(ch->desc) = WLD_TRIGGER; OLC_VAL(ch->desc) = 0; vnum_targ = k; redit_save_internally(ch->desc); cleanup_olc(ch->desc, CLEANUP_STRUCTS); rnum_targ = real_room(vnum_targ); save_zone_2 = save_zone_1; sprintf(buf, "You have created new room #%i.\r\n", vnum_targ); send_to_char(buf, ch); break; } } } /* save_zone_2 has definitely been established. If it's a two * * way exit, don't let them do the linkage. TR 5-21-98 */ if (!can_edit_zone(ch, real_zone(save_zone_2*100)) && type_int == 2) { send_to_char("You cannot create exits in the target zone.\r\n", ch); return; } switch (*direction) { case 'n': case 'N': dir = NORTH; break; case 'e': case 'E': dir = EAST; break; case 's': case 'S': dir = SOUTH; break; case 'w': case 'W': dir = WEST; break; case 'u': case 'U': dir = UP; break; case 'd': case 'D': dir = DOWN; break; default: send_to_char("No such direction!\r\n", ch); return; } if (is_abbrev(command, "connect")) { if (!world[ch->in_room].dir_option[dir]) { create_dir(IN_ROOM(ch), dir); world[IN_ROOM(ch)].dir_option[dir]->to_room = rnum_targ; } else world[IN_ROOM(ch)].dir_option[dir]->to_room = rnum_targ; if (type_int == 2) { if (!world[rnum_targ].dir_option[rev_dir[dir]]) create_dir(rnum_targ, rev_dir[dir]); world[rnum_targ].dir_option[rev_dir[dir]]->to_room = IN_ROOM(ch); if (!save_zone_2) save_zone_2 = zone_number(&world[rnum_targ], ROOM); } } else if (is_abbrev(command, "disconnect")) { if (type_int == 2) { if (world[IN_ROOM(ch)].dir_option[dir]->to_room) { free_dir(world[IN_ROOM(ch)].dir_option[dir]->to_room, rev_dir[dir]); if (world[IN_ROOM(ch)].dir_option[dir]) free_dir(IN_ROOM(ch), dir); else { send_to_char("No such exit!\r\n", ch); return; } save_zone_2 = zone_number(&world[rnum_targ], ROOM); } else { send_to_char("There is no reciprocol exit to remove.\r\n", ch); if (world[IN_ROOM(ch)].dir_option[dir]->to_room) { free_dir(IN_ROOM(ch), dir); } else { send_to_char("No such exit!\r\n", ch); return; } } } else if (type_int == 1) { if (!world[IN_ROOM(ch)].dir_option[dir]->to_room) { send_to_char("No such exit!\r\n", ch); return; } else { free_dir(IN_ROOM(ch), dir); } } else { send_to_char("Invalid disconnect type.\r\n", ch); return; } } else { send_to_char("Invalid command type. Valid choices are connect and disconnect.\r\n", ch); return; } if (is_abbrev(command, "connect")) { sprintf(buf, "You make an exit %s to room %d.\r\n", dirs[dir], vnum_targ); send_to_char(buf, ch); } else send_to_char("Exit deleted.\r\n", ch); olc_add_to_save_list(save_zone_1, OLC_SAVE_ROOM); if (save_zone_2) olc_add_to_save_list(save_zone_2, OLC_SAVE_ROOM); return; }