//*****************************************************************************
//
// redit.c
//
// When room prototypes became python scripts, The room OLC had to be rethought.
// Ideally, all builders would have a basic grasp on python and thus would be
// able to write scripts. Ideally. Sadly, I don't think this can be expected
// out of most builders, and we still need some sort of non-scripting interface
// for editing objs. So here it is...
//
//*****************************************************************************
#include "../mud.h"
#include "../utils.h"
#include "../socket.h"
#include "../world.h"
#include "../zone.h"
#include "../room.h"
#include "../character.h"
#include "../object.h"
#include "../exit.h"
#include "../room_reset.h"
#include "../extra_descs.h"
#include "../prototype.h"
#include "../handler.h"
#include "olc.h"
#include "olc_submenus.h"
#include "olc_extender.h"
//*****************************************************************************
// mandatory modules
//*****************************************************************************
#include "../editor/editor.h"
#include "../scripts/scripts.h"
#include "../scripts/pymudsys.h"
#include "../scripts/script_editor.h"
//*****************************************************************************
// optional modules
//*****************************************************************************
#ifdef MODULE_TIME
#include "../time/mudtime.h"
#endif
#ifdef MODULE_PERSISTENT
#include "../persistent/persistent.h"
#endif
//*****************************************************************************
// room reset olc structs
//*****************************************************************************
typedef struct {
RESET_DATA *reset;
char *locale;
} RESET_OLC;
RESET_OLC *newResetOLC(RESET_DATA *reset, const char *locale) {
RESET_OLC *data = malloc(sizeof(RESET_OLC));
data->reset = reset;
data->locale = strdupsafe(locale);
return data;
}
void deleteResetOLC(RESET_OLC *data) {
if(data->locale) free(data->locale);
free(data);
}
//*****************************************************************************
// room reset list olc structs. Note these are different from RESET_LISTs. This
// is for lists of in/on/then resets that are attached onto other resets.
//*****************************************************************************
typedef struct {
LIST *res_list;
char *locale;
} RESLIST_OLC;
RESLIST_OLC *newReslistOLC(LIST *list, const char *locale) {
RESLIST_OLC *data = malloc(sizeof(RESLIST_OLC));
data->res_list = list;
data->locale = strdupsafe(locale);
return data;
}
void deleteReslistOLC(RESLIST_OLC *data) {
if(data->locale) free(data->locale);
free(data);
}
//*****************************************************************************
// utility functions
//*****************************************************************************
//
// reload a room. used whenever a room is edited and saved
void reload_room(const char *key) {
if(worldRoomLoaded(gameworld, key)) {
PROTO_DATA *proto = worldGetType(gameworld, "rproto", key);
ROOM_DATA *old_room = worldGetRoom(gameworld, key);
ROOM_DATA *new_room = protoRoomRun(proto);
if(new_room != NULL) {
do_mass_transfer(old_room, new_room, TRUE, TRUE, TRUE);
extract_room(old_room);
worldPutRoom(gameworld, key, new_room);
}
}
}
//*****************************************************************************
// functions for printing room reset data
//*****************************************************************************
const char *write_reset_arg(int type, const char *arg, const char *locale) {
static char buf[MAX_BUFFER];
PROTO_DATA *obj = NULL;
PROTO_DATA *mob = NULL;
int pos = atoi(arg);
switch(type) {
case RESET_LOAD_OBJECT:
obj = worldGetType(gameworld, "oproto", get_fullkey_relative(arg, locale));
sprintf(buf, "load %s", (obj ? protoGetKey(obj) : "{RNOTHING{c"));
break;
case RESET_LOAD_MOBILE:
mob = worldGetType(gameworld, "mproto", get_fullkey_relative(arg, locale));
sprintf(buf, "load %s", (mob ? protoGetKey(mob) : "{RNOBODY{c"));
break;
case RESET_POSITION:
sprintf(buf, "change position to %s",
(pos < 0 || pos >= NUM_POSITIONS ? "{RNOTHING{c":posGetName(pos)));
break;
case RESET_FIND_MOBILE:
mob = worldGetType(gameworld, "mproto", get_fullkey_relative(arg, locale));
sprintf(buf, "find %s", (mob ? protoGetKey(mob) : "{RNOBODY{c"));
break;
case RESET_FIND_OBJECT:
obj = worldGetType(gameworld, "oproto", get_fullkey_relative(arg, locale));
sprintf(buf, "find %s", (obj ? protoGetKey(obj) : "{RNOTHING{c"));
break;
case RESET_PURGE_MOBILE:
mob = worldGetType(gameworld, "mproto", get_fullkey_relative(arg, locale));
sprintf(buf, "purge %s", (mob ? protoGetKey(mob) : "{RNOBODY{c"));
break;
case RESET_PURGE_OBJECT:
obj = worldGetType(gameworld, "oproto", get_fullkey_relative(arg, locale));
sprintf(buf, "purge %s", (obj ? protoGetKey(obj) : "{RNOTHING{c"));
break;
case RESET_OPEN:
sprintf(buf, "open/unlock dir %s or container", arg);
break;
case RESET_CLOSE:
sprintf(buf, "close/unlock dir %s or container", arg);
break;
case RESET_LOCK:
sprintf(buf, "close/lock dir %s or container", arg);
break;
case RESET_SCRIPT:
sprintf(buf, "run a script on the parent reset");
break;
default:
sprintf(buf, "UNFINISHED OLC");
break;
}
return buf;
}
int indent_line(char *buf, int buflen, int indent) {
if(indent > 0) {
char fmt[20];
sprintf(fmt, "%%-%ds", indent);
return snprintf(buf, buflen, fmt, " ");
}
return 0;
}
int write_reset_buf(RESET_DATA *reset, char *buf, int buflen, int indent,
bool indent_first, const char *locale) {
int i = 0;
if(indent_first)
i += indent_line(buf, buflen, indent);
i += snprintf(buf+i, buflen-i,
"{c%s with {w%d%% {cchance {w%d {ctime%s (max {w%d{c, rm. {w%d{c)\r\n",
write_reset_arg(resetGetType(reset),resetGetArg(reset), locale),
resetGetChance(reset),
resetGetTimes(reset),
(resetGetTimes(reset) == 1 ? "" : "s"),
resetGetMax(reset),
resetGetRoomMax(reset));
// if we've got ONs, then print 'em all out as well
if(listSize(resetGetOn(reset)) > 0) {
i += indent_line(buf+i, buflen-i, indent);
i += snprintf(buf+i, buflen-i, "{yon it: \r\n");
LIST_ITERATOR *list_i = newListIterator(resetGetOn(reset));
RESET_DATA *next = NULL;
ITERATE_LIST(next, list_i)
i += write_reset_buf(next, buf+i, buflen-i, indent+2, TRUE, locale);
deleteListIterator(list_i);
}
// if we've got INs, then print 'em all out as well
if(listSize(resetGetIn(reset)) > 0) {
i += indent_line(buf+i, buflen-i, indent);
i += snprintf(buf+i, buflen-i, "{yin it: \r\n");
LIST_ITERATOR *list_i = newListIterator(resetGetIn(reset));
RESET_DATA *next = NULL;
ITERATE_LIST(next, list_i)
i += write_reset_buf(next, buf+i, buflen-i, indent+2, TRUE, locale);
deleteListIterator(list_i);
}
// if we've got THENs, print 'em all out as well
if(listSize(resetGetThen(reset)) > 0) {
i += indent_line(buf+i, buflen-i, indent);
i += snprintf(buf+i, buflen-i, "{ywhen successful, also: \r\n");
LIST_ITERATOR *list_i = newListIterator(resetGetThen(reset));
RESET_DATA *next = NULL;
ITERATE_LIST(next, list_i)
i += write_reset_buf(next, buf+i, buflen-i, indent+2, TRUE, locale);
deleteListIterator(list_i);
}
return i;
}
const char *write_reset(RESET_DATA *reset, int indent, bool indent_first,
const char *locale) {
static char buf[MAX_BUFFER];
write_reset_buf(reset, buf, MAX_BUFFER, indent, indent_first, locale);
return buf;
}
//*****************************************************************************
// room reset editing
//*****************************************************************************
// the resedit olc needs these declared
void reslistedit_menu(SOCKET_DATA *sock, RESLIST_OLC *data);
int reslistedit_chooser(SOCKET_DATA *sock, RESLIST_OLC *data,
const char *option);
bool reslistedit_parser(SOCKET_DATA *sock, RESLIST_OLC *data, int choice,
const char *arg);
#define RESEDIT_TYPE 1
#define RESEDIT_TIMES 2
#define RESEDIT_CHANCE 3
#define RESEDIT_MAX 4
#define RESEDIT_ROOM_MAX 5
#define RESEDIT_ARGUMENT 6
void resedit_menu(SOCKET_DATA *sock, RESET_OLC *data) {
send_to_socket(sock,
"{g1) Type: {c%s\r\n"
"{g2) Times: {c%d\r\n"
"{g3) Chance: {c%d\r\n"
"{g4) Max: {c%d\r\n"
"{g5) Room Max: {c%d\r\n"
"{g6) Argument: {c%s\r\n"
"{g7) Load on menu\r\n"
"{g8) Load in menu\r\n"
"{g9) Success menu\r\n"
"---------------------------------------------------------\r\n"
"%s",
resetTypeGetName(resetGetType(data->reset)),
resetGetTimes(data->reset),
resetGetChance(data->reset),
resetGetMax(data->reset),
resetGetRoomMax(data->reset),
(resetGetType(data->reset) != RESET_SCRIPT ?
resetGetArg(data->reset) : ""),
write_reset(data->reset, 0, FALSE, data->locale)
);
if(resetGetType(data->reset) == RESET_SCRIPT) {
send_to_socket(sock, "\r\n");
script_display(sock, resetGetArg(data->reset), FALSE);
}
}
int resedit_chooser(SOCKET_DATA *sock, RESET_OLC *data, const char *option) {
switch(toupper(*option)) {
case '1':
olc_display_table(sock, resetTypeGetName, NUM_RESETS, 1);
text_to_buffer(sock, "Pick a reset type: ");
return RESEDIT_TYPE;
case '2':
text_to_buffer(sock, "How many times should the reset execute: ");
return RESEDIT_TIMES;
case '3':
text_to_buffer(sock, "What is the success chance of the reset: ");
return RESEDIT_CHANCE;
case '4':
text_to_buffer(sock, "What is the max that can exist in game (0 = no limit): ");
return RESEDIT_MAX;
case '5':
text_to_buffer(sock, "What is the max that can exist in room (0 = no limit): ");
return RESEDIT_ROOM_MAX;
case '6':
if(resetGetType(data->reset) == RESET_SCRIPT) {
socketStartEditor(sock, script_editor, resetGetArgBuffer(data->reset));
return MENU_NOCHOICE;
}
else {
text_to_buffer(sock, "What is the reset argument (i.e. obj name, direction, etc...): ");
return RESEDIT_ARGUMENT;
}
case '7':
do_olc(sock, reslistedit_menu, reslistedit_chooser, reslistedit_parser,
NULL, NULL, deleteReslistOLC, NULL,
newReslistOLC(resetGetOn(data->reset), data->locale));
return MENU_NOCHOICE;
case '8':
do_olc(sock, reslistedit_menu, reslistedit_chooser, reslistedit_parser,
NULL, NULL, deleteReslistOLC, NULL,
newReslistOLC(resetGetIn(data->reset), data->locale));
return MENU_NOCHOICE;
case '9':
do_olc(sock, reslistedit_menu, reslistedit_chooser, reslistedit_parser,
NULL, NULL, deleteReslistOLC, NULL,
newReslistOLC(resetGetThen(data->reset), data->locale));
return MENU_NOCHOICE;
default: return MENU_CHOICE_INVALID;
}
}
bool resedit_parser(SOCKET_DATA *sock, RESET_OLC *data, int choice,
const char *arg){
switch(choice) {
case RESEDIT_TYPE: {
int type = atoi(arg);
if(type < 0 || type >= NUM_RESETS)
return FALSE;
resetSetType(data->reset, type);
// set all of the data to defaults
resetSetArg(data->reset, "");
resetSetChance(data->reset, 100);
resetSetMax(data->reset, 0);
resetSetRoomMax(data->reset, 0);
resetSetTimes(data->reset, 1);
return TRUE;
}
case RESEDIT_TIMES: {
int times = atoi(arg);
if(times < 1)
return FALSE;
resetSetTimes(data->reset, times);
return TRUE;
}
case RESEDIT_CHANCE: {
int chance = atoi(arg);
if(chance < 1 || chance > 100)
return FALSE;
resetSetChance(data->reset, chance);
return TRUE;
}
case RESEDIT_MAX: {
int max = atoi(arg);
if(max < 0)
return FALSE;
resetSetMax(data->reset, max);
return TRUE;
}
case RESEDIT_ROOM_MAX: {
int rmax = atoi(arg);
if(rmax < 0)
return FALSE;
resetSetRoomMax(data->reset, rmax);
return TRUE;
}
case RESEDIT_ARGUMENT:
resetSetArg(data->reset, arg);
return TRUE;
default: return FALSE;
}
}
//*****************************************************************************
// room reset list editing
//*****************************************************************************
#define RESLISTEDIT_EDIT 1
#define RESLISTEDIT_DELETE 2
void reslistedit_menu(SOCKET_DATA *sock, RESLIST_OLC *data) {
LIST_ITERATOR *res_i = newListIterator(data->res_list);
RESET_DATA *reset = NULL;
int count = 0;
send_to_socket(sock, "{wCurrent resets:\r\n");
ITERATE_LIST(reset, res_i) {
send_to_socket(sock, " {g%2d) %s", count,
write_reset(reset, 5, FALSE, data->locale));
count++;
} deleteListIterator(res_i);
send_to_socket(sock, "\r\n"
" {gE) edit entry\r\n"
" {gN) new entry\r\n"
" {gD) delete entry\r\n"
);
}
void rrledit_menu(SOCKET_DATA *sock, RESET_LIST *list) {
send_to_socket(sock, "{y[{c%s{y]\r\n", resetListGetKey(list));
RESLIST_OLC *olc = newReslistOLC(resetListGetResets(list),
get_key_locale(resetListGetKey(list)));
reslistedit_menu(sock, olc);
deleteReslistOLC(olc);
}
int reslistedit_chooser(SOCKET_DATA *sock, RESLIST_OLC *list,
const char *option) {
switch(toupper(*option)) {
case 'N': {
RESET_DATA *data = newReset();
listQueue(list->res_list, data);
do_olc(sock, resedit_menu, resedit_chooser, resedit_parser,
NULL, NULL, deleteResetOLC, NULL,
newResetOLC(data, list->locale));
return MENU_NOCHOICE;
}
case 'E':
if(listSize(list->res_list) == 0)
return MENU_CHOICE_INVALID;
text_to_buffer(sock, "Which entry do you want to edit (-1 for none): ");
return RESLISTEDIT_EDIT;
case 'D':
text_to_buffer(sock, "Which entry do you want to delete: ");
return RESLISTEDIT_DELETE;
default:
return MENU_CHOICE_INVALID;
}
}
int rrledit_chooser(SOCKET_DATA *sock, RESET_LIST *list, const char *option) {
RESLIST_OLC *olc = newReslistOLC(resetListGetResets(list),
get_key_locale(resetListGetKey(list)));
int retval = reslistedit_chooser(sock, olc, option);
deleteReslistOLC(olc);
return retval;
}
bool reslistedit_parser(SOCKET_DATA *sock, RESLIST_OLC *list, int choice,
const char *arg) {
switch(choice) {
case RESLISTEDIT_EDIT: {
RESET_DATA *reset = NULL;
if(atoi(arg) == NOTHING)
return TRUE;
if(!isdigit(*arg) ||
(reset = listGet(list->res_list, atoi(arg))) == NULL)
return FALSE;
do_olc(sock, resedit_menu, resedit_chooser, resedit_parser,
NULL, NULL, deleteResetOLC, NULL,
newResetOLC(reset, list->locale));
return TRUE;
}
case RESLISTEDIT_DELETE: {
RESET_DATA *reset = NULL;
if(!isdigit(*arg) ||
(reset = listGet(list->res_list, atoi(arg))) == NULL)
return FALSE;
listRemove(list->res_list, reset);
deleteReset(reset);
return TRUE;
}
default: return FALSE;
}
}
bool rrledit_parser(SOCKET_DATA *sock, RESET_LIST *list, int choice,
const char *arg) {
RESLIST_OLC *olc = newReslistOLC(resetListGetResets(list),
get_key_locale(resetListGetKey(list)));
int retval = reslistedit_parser(sock, olc, choice, arg);
deleteReslistOLC(olc);
return retval;
}
//*****************************************************************************
// exit editing functions
//*****************************************************************************
#define EXEDIT_KEYWORDS 1
#define EXEDIT_LEAVE 2
#define EXEDIT_ENTER 3
#define EXEDIT_TO 4
#define EXEDIT_KEY 5
#define EXEDIT_PICK 6
#define EXEDIT_SPOT 7
#define EXEDIT_NAME 8
#define EXEDIT_OPPOSITE 9
void exedit_menu(SOCKET_DATA *sock, EXIT_DATA *exit) {
send_to_socket(sock,
"{g1) Door name\r\n"
"{c%s\r\n"
"{g2) Door keywords\r\n"
"{c%s\r\n"
"{g3) Leave message\r\n"
"{c%s\r\n"
"{g4) Enter message\r\n"
"{c%s\r\n"
"{g5) Description\r\n"
"{c%s\r\n"
"{g6) Exits to : {c%s\r\n"
"{g7) Key : {c%s\r\n"
"{g8) Closable : {y[{c%6s{y]%s\r\n"
"{g9) Closed : {y[{c%6s{y]\r\n"
"{g0) Locked : {y[{c%6s{y]\r\n"
"{gP) Pick diff : {y[{c%6d{y]\r\n"
"{gS) Spot diff : {y[{c%6d{y]\r\n"
"{gO) Opposite dir: {c%s{n\r\n",
(*exitGetName(exit) ? exitGetName(exit) : "<NONE>"),
(*exitGetKeywords(exit) ? exitGetKeywords(exit) : "<NONE>"),
(*exitGetSpecLeave(exit) ? exitGetSpecLeave(exit):"<DEFAULT>"),
(*exitGetSpecEnter(exit) ? exitGetSpecEnter(exit):"<DEFAULT>"),
exitGetDesc(exit),
exitGetTo(exit),
exitGetKey(exit),
YESNO(exitIsClosable(exit)),
(exitIsClosable(exit) && (!*exitGetName(exit) || !*exitGetKeywords(exit)) ? " {r* exit also needs name and keywords{n" : ""),
YESNO(exitIsClosed(exit)),
YESNO(exitIsLocked(exit)),
exitGetPickLev(exit),
exitGetHidden(exit),
(*exitGetOpposite(exit) ? exitGetOpposite(exit) : "<DEFAULT>")
);
}
int exedit_chooser(SOCKET_DATA *sock, EXIT_DATA *exit, const char *option) {
switch(toupper(*option)) {
case '1':
text_to_buffer(sock, "Enter a new name: ");
return EXEDIT_NAME;
case '2':
text_to_buffer(sock, "Enter a new list of keywords: ");
return EXEDIT_KEYWORDS;
case '3':
text_to_buffer(sock, "Enter a new leave message: ");
return EXEDIT_LEAVE;
case '4':
text_to_buffer(sock, "Enter a new entrance message: ");
return EXEDIT_ENTER;
case '5':
socketStartEditor(sock, text_editor, exitGetDescBuffer(exit));
return MENU_NOCHOICE;
case '6':
text_to_buffer(sock, "Enter a new destination: ");
return EXEDIT_TO;
case '7':
text_to_buffer(sock, "Enter a new key name: ");
return EXEDIT_KEY;
case '8':
exitSetClosable(exit, TOGGLE(exitIsClosable(exit)));
return MENU_NOCHOICE;
case '9':
exitSetClosed(exit, TOGGLE(exitIsClosed(exit)));
return MENU_NOCHOICE;
case '0':
exitSetLocked(exit, TOGGLE(exitIsLocked(exit)));
if(exitIsLocked(exit))
exitSetClosed(exit, TRUE);
return MENU_NOCHOICE;
case 'P':
text_to_buffer(sock, "Enter a new lock difficulty: ");
return EXEDIT_PICK;
case 'S':
text_to_buffer(sock, "Enter a new spot difficulty: ");
return EXEDIT_SPOT;
case 'O':
text_to_buffer(sock, "What is this exit's opposite direction: ");
return EXEDIT_OPPOSITE;
default:
return MENU_CHOICE_INVALID;
}
}
bool exedit_parser(SOCKET_DATA *sock, EXIT_DATA *exit, int choice,
const char *arg) {
switch(choice) {
case EXEDIT_NAME:
exitSetName(exit, arg);
return TRUE;
case EXEDIT_KEYWORDS:
exitSetKeywords(exit, arg);
return TRUE;
case EXEDIT_OPPOSITE:
exitSetOpposite(exit, arg);
return TRUE;
case EXEDIT_LEAVE:
exitSetSpecLeave(exit, arg);
return TRUE;
case EXEDIT_ENTER:
exitSetSpecEnter(exit, arg);
return TRUE;
case EXEDIT_TO:
exitSetTo(exit, arg);
return TRUE;
case EXEDIT_KEY:
exitSetKey(exit, arg);
return TRUE;
case EXEDIT_PICK:
exitSetPickLev(exit, MAX(0, atoi(arg)));
return TRUE;
case EXEDIT_SPOT:
exitSetHidden(exit, MAX(0, atoi(arg)));
return TRUE;
default:
return FALSE;
}
}
//*****************************************************************************
// room olc data
//*****************************************************************************
typedef struct {
char *key; // the key for our prototype
char *parents; // prototypes we inherit from
bool abstract; // can we be loaded into the game?
bool resettable; // do we reset when our zone resets?
ROOM_DATA *room; // our room, which holds most of our variables
RESET_LIST *resets; // non-python reset rules
BUFFER *extra_code; // any extra code that should go into our prototype
} ROOM_OLC;
ROOM_OLC *newRoomOLC(void) {
ROOM_OLC *data = malloc(sizeof(ROOM_OLC));
data->key = strdup("");
data->parents = strdup("");
data->room = newRoom();
data->resets = newResetList();
data->extra_code = newBuffer(1);
data->abstract = TRUE;
data->resettable = FALSE;
roomSetTerrain(data->room, TERRAIN_NONE);
// so python olc extensions can get at us
room_exist(data->room);
return data;
}
void deleteRoomOLC(ROOM_OLC *data) {
room_unexist(data->room);
if(data->key) free(data->key);
if(data->parents) free(data->parents);
if(data->room) deleteRoom(data->room);
if(data->resets) deleteResetList(data->resets);
if(data->extra_code) deleteBuffer(data->extra_code);
free(data);
}
ROOM_DATA *roomOLCGetRoom(ROOM_OLC *data) {
return data->room;
}
RESET_LIST *roomOLCGetResets(ROOM_OLC *data) {
return data->resets;
}
const char *roomOLCGetKey(ROOM_OLC *data) {
return data->key;
}
const char *roomOLCGetParents(ROOM_OLC *data) {
return data->parents;
}
BUFFER *roomOLCGetExtraCode(ROOM_OLC *data) {
return data->extra_code;
}
bool roomOLCGetAbstract(ROOM_OLC *data) {
return data->abstract;
}
bool roomOLCGetResettable(ROOM_OLC *data) {
return data->resettable;
}
void roomOLCSetKey(ROOM_OLC *data, const char *key) {
if(data->key) free(data->key);
data->key = strdupsafe(key);
}
void roomOLCSetParents(ROOM_OLC *data, const char *parents) {
if(data->parents) free(data->parents);
data->parents = strdupsafe(parents);
}
void roomOLCSetAbstract(ROOM_OLC *data, bool abstract) {
data->abstract = abstract;
}
void roomOLCSetResettable(ROOM_OLC *data, bool resettable) {
data->resettable = resettable;
}
//
// sets an exits values, based on a proto script
void exit_from_proto(EXIT_DATA *exit, BUFFER *buf) {
char line[SMALL_BUFFER];
const char *code = bufferString(buf);
do {
char *lptr = line;
code = strcpyto(line, code, '\n');
if(!strcmp(lptr, "exit.makedoor()"))
exitSetClosable(exit, TRUE);
else if(!strncmp(lptr, "exit.name", 9)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[next_letter_in(lptr, '\"')] = '\0'; // kill the ending "
exitSetName(exit, lptr);
}
else if(!strncmp(lptr, "exit.keywords", 13)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[next_letter_in(lptr, '\"')] = '\0'; // kill the ending "
exitSetKeywords(exit, lptr);
}
else if(!strncmp(lptr, "exit.key", 8)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[next_letter_in(lptr, '\"')] = '\0'; // kill the ending "
exitSetKey(exit, lptr);
}
else if(!strncmp(lptr, "exit.opposite", 13)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[next_letter_in(lptr, '\"')] = '\0'; // kill the ending "
exitSetOpposite(exit, lptr);
}
else if(!strncmp(lptr, "exit.leave_mssg", 15)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[next_letter_in(lptr, '\"')] = '\0'; // kill the ending "
exitSetSpecLeave(exit, lptr);
}
else if(!strncmp(lptr, "exit.enter_mssg", 15)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[next_letter_in(lptr, '\"')] = '\0'; // kill the ending "
exitSetSpecEnter(exit, lptr);
}
else if(!strncmp(lptr, "exit.desc", 9)) {
while(*lptr != '\"') lptr++;
lptr++; // kill the leading "
lptr[strlen(lptr) - 1] = '\0'; // kill the ending "
exitSetDesc(exit, lptr);
// replace our \"s with "
bufferReplace(exitGetDescBuffer(exit), "\\\"", "\"", TRUE);
bufferFormat(exitGetDescBuffer(exit), SCREEN_WIDTH, PARA_INDENT);
}
else if(!strncmp(lptr, "exit.pick_diff", 14)) {
while(!isdigit(*lptr)) lptr++;
exitSetPickLev(exit, atoi(lptr));
}
else if(!strncmp(lptr, "exit.spot_diff", 14)) {
while(!isdigit(*lptr)) lptr++;
exitSetHidden(exit, atoi(lptr));
}
} while(*code != '\0');
}
ROOM_OLC *roomOLCFromProto(PROTO_DATA *proto) {
ROOM_OLC *data = newRoomOLC();
ROOM_DATA *room = roomOLCGetRoom(data);
roomOLCSetKey(data, protoGetKey(proto));
roomOLCSetParents(data, protoGetParents(proto));
roomOLCSetAbstract(data, protoIsAbstract(proto));
// build it from the prototype
olc_from_proto(proto, roomOLCGetExtraCode(data), room, roomGetPyFormBorrowed);
bufferFormatFromPy(roomGetDescBuffer(room));
bufferFormat(roomGetDescBuffer(room), SCREEN_WIDTH, PARA_INDENT);
// format the exit desc buffers as well
LIST *ex_list = roomGetExitNames(room);
LIST_ITERATOR *ex_i = newListIterator(ex_list);
char *dir = NULL;
ITERATE_LIST(dir, ex_i) {
bufferFormatFromPy(exitGetDescBuffer(roomGetExit(room, dir)));
bufferFormat(exitGetDescBuffer(roomGetExit(room,dir)),
SCREEN_WIDTH, PARA_INDENT);
} deleteListIterator(ex_i);
deleteListWith(ex_list, free);
// format our extra descriptions
if(edescGetSetSize(roomGetEdescs(room)) > 0) {
LIST_ITERATOR *edesc_i= newListIterator(edescSetGetList(roomGetEdescs(room)));
EDESC_DATA *edesc= NULL;
ITERATE_LIST(edesc, edesc_i) {
bufferFormatFromPy(edescGetDescBuffer(edesc));
bufferFormat(edescGetDescBuffer(edesc), SCREEN_WIDTH, PARA_INDENT);
} deleteListIterator(edesc_i);
}
// do all of our extender data as well
extenderFromProto(redit_extend, room);
return data;
}
//
// Makes a python script out of an exit
void exit_to_proto(EXIT_DATA *exit, BUFFER *buf) {
if(exitIsClosable(exit))
bprintf(buf, "exit.makedoor()\n");
if(exitIsClosed(exit))
bprintf(buf, "exit.close()\n");
if(exitIsLocked(exit))
bprintf(buf, "exit.lock()\n");
if(*exitGetName(exit))
bprintf(buf, "exit.name = \"%s\"\n", exitGetName(exit));
if(*exitGetKeywords(exit))
bprintf(buf, "exit.keywords = \"%s\"\n", exitGetKeywords(exit));
if(*exitGetKey(exit))
bprintf(buf, "exit.key = \"%s\"\n", exitGetKey(exit));
if(*exitGetOpposite(exit))
bprintf(buf, "exit.opposite = \"%s\"\n", exitGetOpposite(exit));
if(*exitGetDesc(exit)) {
BUFFER *desc_copy = bufferCopy(exitGetDescBuffer(exit));
bufferFormatPy(desc_copy);
bprintf(buf, "exit.desc = \"%s\"\n", bufferString(desc_copy));
deleteBuffer(desc_copy);
}
if(exitGetPickLev(exit) > 0)
bprintf(buf, "exit.pick_diff = %d\n", exitGetPickLev(exit));
if(exitGetHidden(exit) > 0)
bprintf(buf, "exit.spot_diff = %d\n", exitGetHidden(exit));
if(*exitGetSpecLeave(exit))
bprintf(buf, "exit.leave_mssg = \"%s\"\n", exitGetSpecLeave(exit));
if(*exitGetSpecEnter(exit))
bprintf(buf, "exit.enter_mssg = \"%s\"\n", exitGetSpecEnter(exit));
}
PROTO_DATA *roomOLCToProto(ROOM_OLC *data) {
PROTO_DATA *proto = newProto();
ROOM_DATA *room = roomOLCGetRoom(data);
BUFFER *buf = protoGetScriptBuffer(proto);
protoSetKey(proto, roomOLCGetKey(data));
protoSetParents(proto, roomOLCGetParents(data));
protoSetAbstract(proto, roomOLCGetAbstract(data));
bprintf(buf, "### The following rproto was generated by redit.\n");
bprintf(buf, "### If you edit this script, adhere to the stylistic\n"
"### conventions laid out by redit, or delete the top line\n");
bprintf(buf, "\n### string values\n");
if(*roomGetName(room))
bprintf(buf, "me.name = \"%s\"\n", roomGetName(room));
if(roomGetTerrain(room) != TERRAIN_NONE)
bprintf(buf, "me.terrain = \"%s\"\n",
terrainGetName(roomGetTerrain(room)));
if(*roomGetDesc(room)) {
BUFFER *desc_copy = bufferCopy(roomGetDescBuffer(room));
bufferFormatPy(desc_copy);
bprintf(buf, "me.desc = me.desc + \" \" + \"%s\"\n",
bufferString(desc_copy));
deleteBuffer(desc_copy);
}
// extra descriptions
if(edescGetSetSize(roomGetEdescs(room)) > 0) {
bprintf(buf, "\n### extra descriptions\n");
LIST_ITERATOR *edesc_i=
newListIterator(edescSetGetList(roomGetEdescs(room)));
EDESC_DATA *edesc= NULL;
ITERATE_LIST(edesc, edesc_i) {
BUFFER *desc_copy = bufferCopy(edescGetDescBuffer(edesc));
bufferFormatPy(desc_copy);
bprintf(buf, "me.edesc(\"%s\", \"%s\")\n",
edescGetKeywords(edesc), bufferString(desc_copy));
deleteBuffer(desc_copy);
} deleteListIterator(edesc_i);
}
if(*bitvectorGetBits(roomGetBits(room))) {
bprintf(buf, "\n### room bits\n");
bprintf(buf, "me.bits = ', '.join([me.bits, \"%s\"])\n",
bitvectorGetBits(roomGetBits(room)));
}
if(listSize(roomGetTriggers(room)) > 0) {
bprintf(buf, "\n### room triggers\n");
LIST_ITERATOR *trig_i = newListIterator(roomGetTriggers(room));
char *trig = NULL;
ITERATE_LIST(trig, trig_i) {
bprintf(buf, "me.attach(\"%s\")\n",get_shortkey(trig,protoGetKey(proto)));
} deleteListIterator(trig_i);
}
// convert exits
LIST *ex_names = roomGetExitNames(room);
LIST_ITERATOR *ex_i = newListIterator(ex_names);
char *ex_name = NULL;
EXIT_DATA *exit = NULL;
ITERATE_LIST(ex_name, ex_i) {
exit = roomGetExit(room, ex_name);
bprintf(buf, "\n### begin exit: %s\n", ex_name);
bprintf(buf, "exit = me.dig(\"%s\", \"%s\")\n",
ex_name, get_shortkey(exitGetTo(exit), protoGetKey(proto)));
exit_to_proto(exit, buf);
bprintf(buf, "### end exit\n");
} deleteListIterator(ex_i);
deleteListWith(ex_names, free);
// do all of our extender data as well
extenderToProto(redit_extend, roomOLCGetRoom(data), buf);
// extra code
if(bufferLength(roomOLCGetExtraCode(data)) > 0) {
bprintf(buf, "\n### begin extra code\n");
bprintf(buf, "%s", bufferString(roomOLCGetExtraCode(data)));
bprintf(buf, "### end extra code\n");
}
return proto;
}
//*****************************************************************************
// room editing functions
//*****************************************************************************
// the different fields of a room we can edit
#define REDIT_PARENTS 2
#define REDIT_NAME 3
#define REDIT_TERRAIN 4
#define REDIT_EXIT 5
#define REDIT_FILL_EXIT 6
#define REDIT_BITVECTOR 7
//
// Display the exits the socket can edit
//
void redit_exit_menu(SOCKET_DATA *sock, ROOM_OLC *data) {
LIST *ex_list = roomGetExitNames(roomOLCGetRoom(data));
LIST_ITERATOR *ex_i = newListIterator(ex_list);
char *dir = NULL;
EXIT_DATA *ex = NULL;
int i = 0;
// first, show all of the standard directions and display an entry for
// them, whether we have an exit or not
for(i = 0; i < NUM_DIRS; i++) {
ex = roomGetExit(roomOLCGetRoom(data), dirGetName(i));
send_to_socket(sock, " {g%-10s : %s%-20s%s",
dirGetName(i),
(ex ? "{c" : "{y" ),
(ex ? get_shortkey(exitGetTo(ex), roomOLCGetKey(data)) : "nowhere"),
(!(i % 2) ? " " : "\r\n"));
}
// now go through our exit list and do all of our special exits
i = 0;
ITERATE_LIST(dir, ex_i) {
if(dirGetNum(dir) == DIR_NONE) {
ex = roomGetExit(roomOLCGetRoom(data), dir);
send_to_socket(sock, " {g%-10s : {c%s%s",
dir, exitGetTo(ex),
(!(i % 2) ? " " : "\r\n"));
i++;
}
} deleteListIterator(ex_i);
deleteListWith(ex_list, free);
// make sure we've printed the last newline if needed
if(i % 2 == 1)
send_to_socket(sock, "\r\n");
}
void redit_menu(SOCKET_DATA *sock, ROOM_OLC *data) {
send_to_socket(sock,
"{y[{c%s{y]\r\n"
"{g1) Abstract: {c%s\r\n"
"{g2) Inherits from prototypes:\r\n"
"{c%s\r\n"
"{g3) Name\r\n{c%s\r\n"
"{g4) Description\r\n{c%s"
"{gL) Land type {y[{c%s{y]\r\n"
"{gB) Set Bits: {c%s\r\n"
"{gZ) Room can be reset: {c%s\r\n"
"{gR) Room reset menu\r\n"
"{gX) Extra descriptions menu\r\n"
"{gT) Trigger menu\r\n"
"{gE) Edit exit\r\n"
"{gF) Fill exit\r\n"
,
roomOLCGetKey(data),
(roomOLCGetAbstract(data) ? "yes" : "no"),
roomOLCGetParents(data),
roomGetName(roomOLCGetRoom(data)),
roomGetDesc(roomOLCGetRoom(data)),
(roomGetTerrain(roomOLCGetRoom(data)) == TERRAIN_NONE ?
"leave unchanged" :
terrainGetName(roomGetTerrain(roomOLCGetRoom(data)))),
bitvectorGetBits(roomGetBits(roomOLCGetRoom(data))),
(roomOLCGetResettable(data) ? "yes" : "no"));
redit_exit_menu(sock, data);
// display our extender info
extenderDoMenu(sock, redit_extend, roomOLCGetRoom(data));
// only allow code editing for people with scripting priviledges
send_to_socket(sock, "\n{gC) Extra code%s\r\n",
((!socketGetChar(sock) ||
!bitIsOneSet(charGetUserGroups(socketGetChar(sock)),
"scripter")) ? " {y({cuneditable{y){g":""));
script_display(sock, bufferString(roomOLCGetExtraCode(data)), FALSE);
}
int redit_chooser(SOCKET_DATA *sock, ROOM_OLC *data, const char *option) {
switch(toupper(*option)) {
case '1':
roomOLCSetAbstract(data, (roomOLCGetAbstract(data) + 1) % 2);
return MENU_NOCHOICE;
case '2':
text_to_buffer(sock,"Enter comma-separated list of rooms to inherit from: ");
return REDIT_PARENTS;
case '3':
text_to_buffer(sock, "Enter a new room name: ");
return REDIT_NAME;
case '4':
text_to_buffer(sock, "Enter a new room description:\r\n");
socketStartEditor(sock, text_editor, roomGetDescBuffer(roomOLCGetRoom(data)));
return MENU_NOCHOICE;
case 'Z':
roomOLCSetResettable(data, (roomOLCGetResettable(data) + 1) % 2);
return MENU_NOCHOICE;
case 'R':
roomOLCSetResettable(data, TRUE);
do_olc(sock, rrledit_menu, rrledit_chooser, rrledit_parser, NULL, NULL,
NULL, NULL, roomOLCGetResets(data));
return MENU_NOCHOICE;
case 'L':
olc_display_table(sock, terrainGetName, NUM_TERRAINS, 3);
text_to_buffer(sock, "Pick a terrain type: ");
return REDIT_TERRAIN;
case 'F':
text_to_buffer(sock, "What is the name of the exit you wish to fill: ");
return REDIT_FILL_EXIT;
case 'E':
text_to_buffer(sock, "What is the name of the exit you wish to edit: ");
return REDIT_EXIT;
case 'X':
do_olc(sock, edesc_set_menu, edesc_set_chooser, edesc_set_parser, NULL,NULL,
NULL, NULL, roomGetEdescs(roomOLCGetRoom(data)));
return MENU_NOCHOICE;
case 'T':
do_olc(sock, trigger_list_menu, trigger_list_chooser, trigger_list_parser,
NULL, NULL, NULL, NULL, roomGetTriggers(roomOLCGetRoom(data)));
return MENU_NOCHOICE;
case 'B':
do_olc(sock, bedit_menu, bedit_chooser, bedit_parser,
NULL, NULL, NULL, NULL, roomGetBits(roomOLCGetRoom(data)));
return MENU_NOCHOICE;
case 'C':
// only scripters can edit extra code
if(!socketGetChar(sock) ||
!bitIsOneSet(charGetUserGroups(socketGetChar(sock)), "scripter"))
return MENU_CHOICE_INVALID;
text_to_buffer(sock, "Edit extra code\r\n");
socketStartEditor(sock, script_editor, roomOLCGetExtraCode(data));
return MENU_NOCHOICE;
default:
return extenderDoOptChoice(sock,redit_extend,roomOLCGetRoom(data),*option);
}
}
bool redit_parser(SOCKET_DATA *sock, ROOM_OLC *data, int choice,
const char *arg) {
switch(choice) {
case REDIT_PARENTS:
roomOLCSetParents(data, arg);
return TRUE;
case REDIT_NAME:
roomSetName(roomOLCGetRoom(data), arg);
return TRUE;
case REDIT_TERRAIN: {
int val = atoi(arg);
if(val < 0 || val >= NUM_TERRAINS)
return FALSE;
roomSetTerrain(roomOLCGetRoom(data), val);
return TRUE;
}
case REDIT_FILL_EXIT: {
EXIT_DATA *old_exit = NULL;
const char *dir = arg;
// are we trying to reference by its abbreviation?
if(!roomGetExit(roomOLCGetRoom(data), dir) && dirGetAbbrevNum(arg) != DIR_NONE)
dir = dirGetName(dirGetAbbrevNum(dir));
old_exit = roomRemoveExit(roomOLCGetRoom(data), dir);
// delete the exit...
if(old_exit != NULL) {
// is our room in the game? do we need to remove the exit from game?
if(propertyTableIn(room_table, roomGetUID(roomOLCGetRoom(data))))
exit_from_game(old_exit);
deleteExit(old_exit);
}
return TRUE;
}
case REDIT_EXIT: {
if(!*arg)
return FALSE;
else {
EXIT_DATA *exit = NULL;
const char *dir = arg;
// are we trying to reference by its abbreviation?
if(!roomGetExit(roomOLCGetRoom(data), dir) && dirGetAbbrevNum(arg) != DIR_NONE)
dir = dirGetName(dirGetAbbrevNum(dir));
exit = roomGetExit(roomOLCGetRoom(data), dir);
// do we need to supply a new exit?
if(exit == NULL) {
exit = newExit();
// are we editing a room in game? If so, add this exit to the game
if(propertyTableIn(room_table, roomGetUID(roomOLCGetRoom(data))))
exit_to_game(exit);
roomSetExit(roomOLCGetRoom(data), dir, exit);
}
// enter the exit editor
do_olc(sock, exedit_menu, exedit_chooser, exedit_parser, NULL, NULL,
NULL, NULL, exit);
return TRUE;
}
}
default:
return extenderDoParse(sock,redit_extend,roomOLCGetRoom(data),choice,arg);
}
}
void save_rreset(RESET_LIST *list) {
if(listSize(resetListGetResets(list)) > 0)
worldSaveType(gameworld, "reset", resetListGetKey(list));
else {
worldRemoveType(gameworld, "reset", resetListGetKey(list));
worldSaveType(gameworld, "reset", resetListGetKey(list));
deleteResetList(list);
}
}
void save_room_olc(ROOM_OLC *data) {
PROTO_DATA *old_proto = worldGetType(gameworld, "rproto",roomOLCGetKey(data));
PROTO_DATA *new_proto = roomOLCToProto(data);
RESET_LIST *old_reset = worldGetType(gameworld, "reset", roomOLCGetKey(data));
RESET_LIST *new_reset = roomOLCGetResets(data);
ZONE_DATA *zone =
worldGetZone(gameworld, get_key_locale(roomOLCGetKey(data)));
// save our room proto
if(old_proto == NULL)
worldPutType(gameworld, "rproto", protoGetKey(new_proto), new_proto);
else {
protoCopyTo(new_proto, old_proto);
deleteProto(new_proto);
}
// save our resets
if(old_reset == NULL && listSize(resetListGetResets(new_reset)) > 0)
worldPutType(gameworld, "reset", roomOLCGetKey(data),
resetListCopy(new_reset));
else if(old_reset != NULL)
resetListCopyTo(new_reset, old_reset);
else if(old_reset != NULL && listSize(resetListGetResets(new_reset)) == 0) {
worldRemoveType(gameworld, "reset", roomOLCGetKey(data));
deleteResetList(old_reset);
}
// check to see if we should reset this room even if it's not visited yet
if(roomOLCGetResettable(data) &&
!listGetWith(zoneGetResettable(zone),
get_key_name(roomOLCGetKey(data)),
strcasecmp))
listPut(zoneGetResettable(zone), strdup(get_key_name(roomOLCGetKey(data))));
else if(!roomOLCGetResettable(data)) {
char *found = listRemoveWith(zoneGetResettable(zone),
get_key_name(roomOLCGetKey(data)),
strcasecmp);
if(found) zoneSave(zone);
}
worldSaveType(gameworld, "rproto", roomOLCGetKey(data));
worldSaveType(gameworld, "reset", roomOLCGetKey(data));
zoneSave(zone);
// force-reset our room
reload_room(roomOLCGetKey(data));
}
//*****************************************************************************
// commands
//*****************************************************************************
COMMAND(cmd_resedit) {
ZONE_DATA *zone = NULL;
RESET_LIST *resets = NULL;
const char *rkey = arg;
// we need a key
if(!rkey || !*rkey)
rkey = roomGetClass(charGetRoom(ch));
else if(key_malformed(rkey)) {
send_to_char(ch, "You entered an invalid content key.\r\n");
return;
}
char locale[SMALL_BUFFER];
char name[SMALL_BUFFER];
if(!parse_worldkey_relative(ch, rkey, name, locale))
send_to_char(ch, "Which room are you trying to edit?\r\n");
// make sure we can edit the zone
else if((zone = worldGetZone(gameworld, locale)) == NULL)
send_to_char(ch, "No such zone exists.\r\n");
else if(!canEditZone(zone, ch))
send_to_char(ch, "You are not authorized to edit that zone.\r\n");
else {
// try to pull up the reset
resets = worldGetType(gameworld, "reset", get_fullkey(name, locale));
// if we don't already have a reset, make one
if(resets == NULL) {
resets = newResetList();
worldPutType(gameworld, "reset", get_fullkey(name, locale), resets);
}
do_olc(charGetSocket(ch), rrledit_menu, rrledit_chooser, rrledit_parser,
resetListCopy, resetListCopyTo, deleteResetList, save_rreset,
resets);
}
}
bool do_fill(ROOM_DATA *room, const char *dir) {
#ifdef MODULE_PERSISTENT
if(roomIsPersistent(room)) {
EXIT_DATA *exit = roomRemoveExit(room, dir);
if(exit != NULL) {
exit_from_game(exit);
deleteExit(exit);
}
// is it a special exit? If so, we may need to remove the command as well
if(dirGetNum(dir) == DIR_NONE) {
CMD_DATA *cmd = roomRemoveCmd(room, dir);
if(cmd != NULL)
deleteCmd(cmd);
}
// save our change
worldStorePersistentRoom(gameworld, roomGetClass(room), room);
}
else
#endif
{
PROTO_DATA *proto = worldGetType(gameworld, "rproto", roomGetClass(room));
// parse a room OLC out of it
ROOM_OLC *olc = roomOLCFromProto(proto);
if(olc == NULL)
return FALSE;
// delete our exits
EXIT_DATA *exit = roomRemoveExit(roomOLCGetRoom(olc), dir);
if(exit != NULL) {
exit_from_game(exit);
deleteExit(exit);
}
// is it a special exit? If so, we may need to remove the command as well
if(dirGetNum(dir) == DIR_NONE) {
CMD_DATA *cmd = roomRemoveCmd(room, dir);
if(cmd != NULL)
deleteCmd(cmd);
}
// add in our resets so they don't get wiped during saving
RESET_LIST *resets = worldGetType(gameworld, "reset", roomGetClass(room));
if(resets != NULL)
resetListCopyTo(resets, roomOLCGetResets(olc));
if(listGetWith(zoneGetResettable(worldGetZone(gameworld, get_key_locale(roomGetClass(room)))),
get_key_name(roomGetClass(room)),
strcasecmp) != NULL)
roomOLCSetResettable(olc, TRUE);
// save our changes and reload the room
save_room_olc(olc);
// garbage collection
deleteRoomOLC(olc);
}
return TRUE;
}
bool do_dig(ROOM_DATA *from, ROOM_DATA *to, const char *dir) {
#ifdef MODULE_PERSISTENT
// are we in a persistent room?
if(roomIsPersistent(from)) {
EXIT_DATA *exit = newExit();
exitSetTo(exit, roomGetClass(to));
roomSetExit(from, dir, exit);
exit_to_game(exit);
// if it is a special exit and we have a registered movement command,
// add a special command to the room to use this exit
if(dirGetNum(dir) == DIR_NONE && get_cmd_move() != NULL) {
CMD_DATA *cmd = newPyCmd(dir, get_cmd_move(), "player", TRUE);
// add all of our movement checks
LIST_ITERATOR *chk_i = newListIterator(get_move_checks());
PyObject *chk = NULL;
ITERATE_LIST(chk, chk_i) {
cmdAddPyCheck(cmd, chk);
} deleteListIterator(chk_i);
//cmdAddCheck(cmd, chk_can_move);
roomAddCmd(from, dir, NULL, cmd);
}
// save our change
worldStorePersistentRoom(gameworld, roomGetClass(from), from);
}
// load up the rproto and edit it
else
#endif
{
// get the prototype for our current room
PROTO_DATA *proto =
worldGetType(gameworld, "rproto", roomGetClass(from));
// parse a ROOM_OLC out of it
ROOM_OLC *olc = roomOLCFromProto(proto);
// error occured
if(olc == NULL)
return FALSE;
// make our exits
EXIT_DATA *exit = newExit();
exitSetTo(exit, roomGetClass(to));
// link our rooms
roomSetExit(roomOLCGetRoom(olc), dir, exit);
// re-update our resets
RESET_LIST *resets =
worldGetType(gameworld, "reset", roomGetClass(from));
if(resets != NULL)
resetListCopyTo(resets, roomOLCGetResets(olc));
if(listGetWith(zoneGetResettable(worldGetZone(gameworld, get_key_locale(roomGetClass(from)))),
get_key_name(roomGetClass(from)),
strcasecmp) != NULL)
roomOLCSetResettable(olc, TRUE);
// save our changes and reload the rooms
save_room_olc(olc);
deleteRoomOLC(olc);
}
return TRUE;
}
COMMAND(cmd_dig) {
ROOM_DATA *dest = NULL;
char *parsed_dir = NULL;
char *parsed_ret_dir = NULL;
char *ret_dir = NULL;
char *dir = NULL;
// parse our arguments
if(!parse_args(ch, TRUE, cmd, arg, "room word | word",
&dest, &parsed_dir, &parsed_ret_dir))
return;
// figure out our direction
if(dirGetAbbrevNum(parsed_dir) != DIR_NONE)
dir = strdup(dirGetName(dirGetAbbrevNum(parsed_dir)));
// special exit
else
dir = strdup(parsed_dir);
// figure out our return direction. First case == special exit
if(parsed_ret_dir != NULL)
ret_dir = strdup(parsed_ret_dir);
else if(dirGetNum(dir) != DIR_NONE)
ret_dir = strdup(dirGetName(dirGetOpposite(dirGetNum(dir))));
else if(dirGetAbbrevNum(dir) != DIR_NONE)
ret_dir = strdup(dirGetName(dirGetOpposite(dirGetAbbrevNum(dir))));
// make sure we don't have an exit in the specified direction
if(roomGetExit(charGetRoom(ch), dir) != NULL)
send_to_char(ch, "An exit already exists %s -- fill it first!\r\n",
dir);
// make sure we don't have an exit in the return direction
else if(ret_dir && roomGetExit(dest, ret_dir) != NULL)
send_to_char(ch, "An exit already exists in the return direction -- fill it first!\r\n");
// make sure we have edit priviledges
else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(charGetRoom(ch)))), ch))
send_to_char(ch, "You are not authorized to edit this zone.\r\n");
// make sure we have edit priviledges for the destination
else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(dest))), ch))
send_to_char(ch,"You are not authorized to edit the destination zone.\r\n");
// do the digging
else {
if(do_dig(charGetRoom(ch), dest, dir))
send_to_char(ch, "You link %s to %s [%s].\r\n",
roomGetClass(charGetRoom(ch)), roomGetClass(dest), dir);
else {
send_to_char(ch, "An error occured while digging to %s.",
roomGetClass(dest));
}
if(ret_dir && do_dig(dest, charGetRoom(ch), ret_dir))
send_to_char(ch, "You link %s to %s [%s].\r\n",
roomGetClass(dest), roomGetClass(charGetRoom(ch)), ret_dir);
else if(ret_dir) {
send_to_char(ch, "An error occured while digging a return to %s.",
roomGetClass(charGetRoom(ch)));
}
}
// garbage collection
free(dir);
free(ret_dir);
}
COMMAND(cmd_fill) {
ROOM_DATA *dest = NULL;
char *parsed_dir = NULL;
char *parsed_ret_dir = NULL;
char *ret_dir = NULL;
char *dir = NULL;
// parse our arguments
if(!parse_args(ch, TRUE, cmd, arg, "word | word",
&parsed_dir, &parsed_ret_dir))
return;
// figure out our direction
if(dirGetAbbrevNum(parsed_dir) != DIR_NONE)
dir = strdup(dirGetName(dirGetAbbrevNum(parsed_dir)));
// special exit
else
dir = strdup(parsed_dir);
// figure out our return direction. First case == special exit
if(parsed_ret_dir != NULL)
ret_dir = strdup(parsed_ret_dir);
else if(dirGetNum(dir) != DIR_NONE)
ret_dir = strdup(dirGetName(dirGetOpposite(dirGetNum(dir))));
else if(dirGetAbbrevNum(dir) != DIR_NONE)
ret_dir = strdup(dirGetName(dirGetOpposite(dirGetAbbrevNum(dir))));
// make sure we have the exit
if(!roomGetExit(charGetRoom(ch), dir))
send_to_char(ch, "No exit exists %s!\r\n", dir);
// make sure the destination exists
else if((dest = worldGetRoom(gameworld,exitGetToFull(roomGetExit(charGetRoom(ch),
dir)))) == NULL)
send_to_char(ch, "No destination exists %s!\r\n", dir);
// make sure we have edit priviledges
else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(charGetRoom(ch)))), ch))
send_to_char(ch, "You are not authorized to edit this zone.\r\n");
// make sure we have edit priviledges for the destination
else if(!canEditZone(worldGetZone(gameworld, get_key_locale(roomGetClass(dest))), ch))
send_to_char(ch,"You are not authorized to edit the destination zone.\r\n");
// do the filling
else {
if(do_fill(charGetRoom(ch), dir))
send_to_char(ch, "You unlink %s [%s].\r\n",
roomGetClass(charGetRoom(ch)), dir);
else {
send_to_char(ch, "An error occured while filling %s %s.",
roomGetClass(charGetRoom(ch)), dir);
}
if(ret_dir && do_fill(dest, ret_dir))
send_to_char(ch, "You unlink %s [%s].\r\n", roomGetClass(dest), ret_dir);
else if(ret_dir) {
send_to_char(ch, "An error occured while filling %s %s.",
roomGetClass(dest), ret_dir);
}
}
// garbage collection
free(dir);
free(ret_dir);
}
//
// builds a list of all the instantiations in the range provided
LIST *list_instantiations(const char *name, const char *locale, int times) {
LIST *list = newList();
int i, base_i = 1;
char *working_name = strdup(name);
// see if we have a start number provided
//***********
// FINISH ME
//***********
// generate our keys
for(i = base_i; i < times + base_i; i++) {
char fullkey[SMALL_BUFFER];
sprintf(fullkey, "%s%s%d@%s", working_name, (i < 10 ? "0" : ""), i, locale);
listQueue(list, strdup(fullkey));
}
// garbage collection
free(working_name);
return list;
}
//
// checks to see if any of the rooms are already cloned
bool check_for_instantiations(CHAR_DATA *ch, const char *name, const char *locale, int times) {
LIST *keys = list_instantiations(name, locale, times);
LIST_ITERATOR *key_i = newListIterator(keys);
char *key = NULL;
bool success = TRUE;
ITERATE_LIST(key, key_i) {
// check for the existance
if(worldGetType(gameworld, "rproto", key) != NULL) {
send_to_char(ch, "A prototype with key %s already exists.", key);
success = FALSE;
break;
}
} deleteListIterator(key_i);
deleteListWith(keys, free);
return success;
}
COMMAND(cmd_instantiate) {
ZONE_DATA *dest_zone = NULL;
ZONE_DATA *src_zone = NULL;
char *dest = NULL;
char *src = NULL;
char dest_locale[SMALL_BUFFER];
char dest_name[SMALL_BUFFER];
char src_locale[SMALL_BUFFER];
char src_name[SMALL_BUFFER];
int times = 1;
// rcopy <source> <dest> [times]
if(!parse_args(ch, TRUE, cmd, arg, "word word | int", &src, &dest, ×))
return;
// get our locale and name for the source
else if(!parse_worldkey_relative(ch, src, src_name, src_locale))
send_to_char(ch, "What is the key of the source room?\r\n");
// get our locale and name for the dest
else if(!parse_worldkey_relative(ch, dest, dest_name, dest_locale))
send_to_char(ch, "What is the key of the destination room?\r\n");
else if(key_malformed(src) || key_malformed(dest))
send_to_char(ch, "Malformed source or destination keys.");
// make sure the destination zone is editable
else if((dest_zone = worldGetZone(gameworld, dest_locale)) == NULL)
send_to_char(ch, "No such destination zone exists.\r\n");
else if((src_zone = worldGetZone(gameworld, src_locale)) == NULL)
send_to_char(ch, "No such source zone exists.\r\n");
// make sure we have editing priviledges
else if(!canEditZone(dest_zone, ch))
send_to_char(ch,"You are not authorized to edit the destination zone.\r\n");
// make sure none of the prototypes we'll be making are instantiated
else if(!check_for_instantiations(ch, src_name, src_locale, times))
return;
else {
// generate our list of keys
LIST *keys = list_instantiations(dest_name, dest_locale, times);
LIST_ITERATOR *key_i = newListIterator(keys);
char *key = NULL;
bool resettable = FALSE;
// check to see if the source room is resettable
if(listGetWith(zoneGetResettable(src_zone), src_name, strcasecmp) != NULL)
resettable = TRUE;
// create each of the rooms to be cloned
ITERATE_LIST(key, key_i) {
const char *src_fullkey = get_fullkey(src_name, src_locale);
ROOM_OLC *data = newRoomOLC();
roomOLCSetKey(data, key);
resetListSetKey(roomOLCGetResets(data), key);
roomOLCSetAbstract(data, FALSE);
roomOLCSetResettable(data, resettable);
roomOLCSetParents(data, get_shortkey(src_fullkey, key));
save_room_olc(data);
deleteRoomOLC(data);
} deleteListIterator(key_i);
deleteListWith(keys, free);
send_to_char(ch, "You create %d new instantion%s of %s@%s.\r\n",
times, (times == 1 ? "":"s"), src_name, src_locale);
}
}
COMMAND(cmd_redit) {
ZONE_DATA *zone = NULL;
PROTO_DATA *proto = NULL;
RESET_LIST *resets = NULL;
const char *rkey = arg;
// we need a key
if(!rkey || !*rkey)
rkey = roomGetClass(charGetRoom(ch));
else if(key_malformed(rkey)) {
send_to_char(ch, "You entered an invalid content key.\r\n");
return;
}
char locale[SMALL_BUFFER];
char name[SMALL_BUFFER];
if(!parse_worldkey_relative(ch, rkey, name, locale))
send_to_char(ch, "Which room are you trying to edit?\r\n");
// make sure we can edit the zone
else if((zone = worldGetZone(gameworld, locale)) == NULL)
send_to_char(ch, "No such zone exists.\r\n");
else if(!canEditZone(zone, ch))
send_to_char(ch, "You are not authorized to edit that zone.\r\n");
else {
// try to make our OLC datastructure
ROOM_OLC *data = NULL;
// try to pull up the prototype
proto = worldGetType(gameworld, "rproto", get_fullkey(name, locale));
resets = worldGetType(gameworld, "reset", get_fullkey(name, locale));
// if we already have proto data, try to parse an obj olc out of it
if(proto != NULL) {
// check to make sure the prototype was made by redit
char line[SMALL_BUFFER];
strcpyto(line, protoGetScript(proto), '\n');
if(strcmp(line, "### The following rproto was generated by redit.") != 0){
send_to_char(ch, "This room was not generated by redit and potential "
"formatting problems prevent redit from being used. To "
"edit, rpedit must be used.\r\n");
return;
}
else {
data = roomOLCFromProto(proto);
if(resets != NULL)
resetListCopyTo(resets, roomOLCGetResets(data));
else
resetListSetKey(roomOLCGetResets(data), get_fullkey(name, locale));
}
}
// otherwise, make a new obj olc and assign its key
else {
data = newRoomOLC();
roomOLCSetKey(data, get_fullkey(name, locale));
resetListSetKey(roomOLCGetResets(data), get_fullkey(name, locale));
roomOLCSetAbstract(data, TRUE);
ROOM_DATA *room = roomOLCGetRoom(data);
roomSetName (room, "an unfinished room");
roomSetDesc (room, "it looks unfinished.\r\n");
}
if(listGetWith(zoneGetResettable(zone),
get_key_name(roomOLCGetKey(data)),
strcasecmp) != NULL)
roomOLCSetResettable(data, TRUE);
do_olc(charGetSocket(ch), redit_menu, redit_chooser, redit_parser,
NULL, NULL, deleteRoomOLC, save_room_olc, data);
}
}