/***********************************************************
Realms of Aurealis Online Creation System version 2.1
RoAOLCv2.1 - James Rhone aka Vall of RoA
roaolc.c (online creation system - mob/room/object/house edit files)
Adopted from Realms of Imagination's original version of OLC (7/95)
******** Heavily modified and expanded ********
*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
******** Heavily modified and expanded ********
All rights reserved henceforth. Author: James Rhone
Original Running Version: 0.5beta
Please note that no guarantees are associated with any code from
Realms of Aurealis. All code which has been released to the general
public has been done so with an 'as is' pretense. Thanks to Jeremy Elson
who has provided a stable base for Realms of Aurealis. RoA was originally
created from a CircleMUD 2.2 base, back in the dark ages, when even that
release was considered new wave.
Since RoA is a perpetual BETA MUD, all code from it is also in BETA
stages. I personally feel this is the best OLC ever made available for
CircleMUD and its derivatives. My experienced builders agree. How you
feel depends on how well you can fit into your mud. Good luck. There are
no patch files, no step by step instructions, and no hand holders. All
code written for Realms of Aurealis, including that contained in this file
was written by me, James Rhone, so nobody is very familiar with it except
me. Perhaps that will change. :)
***
If you do not know C, I suggest getting to know it before you attempt
to plug this into your mud. This is not a trivial addition to any mud and
without someone there to guide you, you will inevitably get frustrated.
**
note: zone OLC can be found in z_olc.c
note: room OLC can be found in r_olc.c
note: mobile OLC can be found in m_olc.c
note: object OLC can be found in o_olc.c
**********************************************************/
#include "conf.h"
#include "sysdep.h"
#include "structures.h"
#include "comm.h"
#include "interpreter.h"
#include "acmd.h"
#include "db.h"
#include "utils.h"
#include "mudlimits.h"
#include "handler.h"
#include "roaolc.h"
#include "magic.h"
#include "house.h"
#include "lists.h"
#include "global.h"
#include "clicomm.h"
// external functions and variables
extern char *dirs[];
extern char *room_bits[];
extern exdescdata *correct_extra_descrips(exdescdata *ths);
// no more duping this bit of code...
BOOL olc_perms(chdata *ch, int level_override, int zone)
{
if (GET_LEVEL(ch) < level_override &&
(zone == 0 || zone < ch->pc_specials->saved.olc_min_zone ||
zone > ch->pc_specials->saved.olc_max_zone))
{
send_to_char("RoAOLC: Insufficient permissions.\n\r",ch);
return FALSE;
}
else
return TRUE;
}
// send version and menu title to char in RoAOLC
void menu_title_send(char *menu, chdata *ch)
{
char buf[MAX_STRING_LENGTH];
if (PLR_FLAGGED(ch, PLR_REFRESH))
clrscr(ch);
sprintf(buf, "\n\r %%B%%5%s %s%%0\n\r", OLC_version, menu);
S2C();
}
// assigning / revocation of building privs
ACMD(do_olc)
{
char buf[MAX_STRING_LENGTH];
char func[MAX_STRING_LENGTH];
chdata *person;
int min_zone, max_zone;
if (IS_NPC(ch))
return;
if (*argument)
{
argument = one_argument(argument, buf);
person = get_char_vis(ch, buf);
}
else
person = ch;
if (!person)
{
send_to_char("No such person is around.\n\r", ch);
return;
}
if (IS_NPC(person))
{
send_to_char("NPC's don't have OLC privileges.\n\r", ch);
return;
}
if (!IS_IMMORTAL(person))
{
send_to_char("Must be immortal.\n\r",ch);
return;
}
if (GET_LEVEL(person) > GET_LEVEL(ch))
{
send_to_char("Pick on someone your own size.\n\r", ch);
return;
}
if (*argument && GET_LEVEL(ch) >= LEV_AIMP)
{
argument = one_argument(argument, func);
if (!*argument || !strlen(func))
{
send_to_char("usage: OLC <player> all <min zone> [<max zone>]\n\r", ch);
return;
}
argument = one_argument(argument, buf);
min_zone = atoi(buf);
if (!*argument)
max_zone = min_zone;
else
{
argument = one_argument(argument, buf);
max_zone = atoi(buf);
}
if (max_zone < min_zone)
{
send_to_char("The maximum zone must be greater or "
"equal to the minimum zone.\n\r", ch);
return;
}
person->pc_specials->saved.olc_min_zone = min_zone;
person->pc_specials->saved.olc_max_zone = max_zone;
}
act("RoAOLC privs for $N:", FALSE,ch,0,person,TO_CHAR);
sprintf(buf, "Zones: %3d - %3d\n\r", person->pc_specials->saved.olc_min_zone,
person->pc_specials->saved.olc_max_zone);
S2C();
}
// list rooms/chars in a particular zone
ACMD(do_zlist)
{
rmdata *w;
chdata *x;
int zone;
int i, top;
char buf[20000];
if (IS_NPC(ch))
return;
one_argument(argument, buf);
if (!*buf || *buf == '.')
zone = world[ch->in_room].zone;
else
zone = real_zone(atoi(buf));
if (zone < 0)
{
send_to_char("That zone does not exist.\n\r",ch);
return;
}
if (!olc_perms(ch, LEV_GOD, zone))
return;
if (ZONE_FREED(zone))
{
send_to_char("The rooms from that zone are not stored in memory.\n\r",ch);
send_to_char("Use %Bzlock%0 to load them into memory.\n\r",ch);
return;
}
top = zone_table[zone].top;
for (i = zone * 100; i <= top; i++)
{
if (real_room(i) >= 0)
break;
}
if (i > top)
return;
buf[0] = '\0';
while (i <= top)
{
if (real_room(i) < 0)
{
i++;
continue;
}
w = &world[real_room(i)];
sprintf(buf1, "[%%B%%6%5d%%0]\t%-22.22s%%0\t", i, w->name);
sprintbit(w->room_flags, room_bits, buf2);
strcat(buf1, buf2);
strcat(buf1, "\n\r");
x = w->people;
while (x)
{
if (IS_NPC(x))
sprintf(buf2, "\t[%%B%2d NPC%%0] %s\n\r", GET_LEVEL(x), x->player.name);
else
sprintf(buf2, "\t[%%5%2d %s%%0] %s\n\r", GET_LEVEL(x), CLASS_ABBR(x),
x->player.name);
strcat(buf1, buf2);
strcat(buf, buf1);
*buf1 = '\0';
x = x->next_in_room;
}
i++;
}
page_string(ch->desc, buf, 1);
}
/* simply toggles clrscreen flag for builders */
ACMD(do_refresh)
{
if (IS_NPC(ch)) return;
if (!PLR_FLAGGED(ch, PLR_REFRESH))
{
SET_BIT(PLR_FLAGS(ch), PLR_REFRESH);
send_to_char("%5OLC refresh %Bon%0.\n\r",ch);
return;
}
REMOVE_BIT(PLR_FLAGS(ch), PLR_REFRESH);
send_to_char("%5OLC refresh %Boff%0.\n\r",ch);
}
// throw a string into a file -roa
void string_to_file(char *text, char *fname)
{
FILE *fp;
char buffer[85000];
strcpy(buffer, text);
killr(buffer);
if (!(fp = fopen(fname, "wt")))
{
sprintf(buf, "SYSERR: Could not open %s.", fname);
return;
}
fprintf(fp, "%s", buffer);
fclose(fp);
}
// dont push onto the stack, just jump char to this menu
int menu_jump(chdata *ch, void (*to_menu)(chdata *ch, char *input_str))
{
MENU_HANDLER(ch) = to_menu;
(*MENU_HANDLER(ch))(ch, NULL);
return 1;
}
// throw current onto stack, then jump
int menu_push_jump(chdata *ch, void (*to_menu)(chdata *ch, char *input_str))
{
menu_push(ch);
MENU_HANDLER(ch) = to_menu;
(*MENU_HANDLER(ch))(ch, NULL);
return 1;
}
// OK, i'll attempt to spawn off a diff editor, after they are done
// ill put the file they editted into d->str
// then call string_add
int do_max_string_arg(chdata *ch, char *prompt, char **return_ptr)
{
char shellfname[100];
char fname[100];
BOOL cliedit = FALSE;
extern void startshell(dsdata *d, char *x, char *y);
menu_push(ch);
// RoA
// OK, if using alternate editor for these large files
// write the current *return_ptr to their edit file so
// spico can read it
if (PLR_FLAGGED(ch, PLR_EXEDIT))
{
sprintf(fname, "edits/%s.edit", GET_NAME(ch));
// delete the file if it exists
if (unlink(fname) < 0) {
if (errno != ENOENT) { /* if it fails, NOT because of no file */
sprintf(buf1, "SYSERR: deleting edit file %s (2)", fname);
perror(buf1);
}
}
}
// add ability to send string to client for editing
// 2/25/98 -jtrhone
if (PLR2_FLAGGED(ch, PLR2_CLIEDIT) && ch->desc && HAS_CLIENT(ch->desc))
cliedit = TRUE;
if (*return_ptr)
{
if (PLR_FLAGGED(ch, PLR_EXEDIT))
string_to_file(*return_ptr, fname);
else
if (cliedit)
{
client_edit(ch->desc, prompt, *return_ptr);
send_to_char("Switch to RoAClient...", ch);
}
free_log(*return_ptr, "do_max_string_arg");
}
*return_ptr = NULL;
MENU_HANDLER(ch) = menu_long_string;
ch->desc->max_str = MAX_STRING_LENGTH - 3;
ch->desc->str = return_ptr;
if (PLR_FLAGGED(ch, PLR_EXEDIT))
{
MENU_PROMPT(ch) = NULL;
sprintf(shellfname, "%s.edit", GET_NAME(ch));
startshell(ch->desc, "", shellfname);
}
else
if (cliedit)
{
MENU_PROMPT(ch) = NULL;
}
else
{
send_to_char(prompt, ch);
MENU_PROMPT(ch) = NULL;
}
return 0;
}
// set character into classic string editting mode (like writing boards)
// multi line text entry, will use cliedit now if chosen 7/9/98 -jtrhone
int do_long_string_arg(chdata *ch, char *prompt, char **return_ptr)
{
BOOL cliedit = FALSE;
menu_push(ch);
if (PLR2_FLAGGED(ch, PLR2_CLIEDIT) && ch->desc && HAS_CLIENT(ch->desc))
cliedit = TRUE;
if (*return_ptr)
{
if (cliedit)
{
client_edit(ch->desc, prompt, *return_ptr);
send_to_char("Switch to RoAClient...", ch);
}
free_log(*return_ptr, "do_long_string_arg");
}
*return_ptr = NULL;
MENU_HANDLER(ch) = menu_long_string;
ch->desc->max_str = 1000;
ch->desc->str = return_ptr;
if (!cliedit)
send_to_char(prompt, ch);
MENU_PROMPT(ch) = NULL;
return 0;
}
// sends character into exshell editor if they are flagged to do so
// currently used for mobprocs and IMPL room descrips perhaps
int do_var_string_arg(chdata *ch, char *prompt, char **return_ptr, int length)
{
char shellfname[100];
char fname[100];
BOOL cliedit = FALSE;
extern void startshell(dsdata *d, char *x, char *y);
menu_push(ch);
// RoA
// OK, if using alternate editor for these large files
// write the current *return_ptr to their edit file so
// spico can read it
if (PLR_FLAGGED(ch, PLR_EXEDIT))
{
sprintf(fname, "edits/%s.edit", GET_NAME(ch));
unlink(fname);
if (*return_ptr)
string_to_file(*return_ptr, fname);
}
// add ability to send string to client for editing
// 2/25/98 -jtrhone
if (PLR2_FLAGGED(ch, PLR2_CLIEDIT) && ch->desc && HAS_CLIENT(ch->desc))
{
cliedit = TRUE;
client_edit(ch->desc, prompt, *return_ptr);
send_to_char("Switch to RoAClient...", ch);
}
if (*return_ptr)
free_log(*return_ptr, "do_var_string_arg");
*return_ptr = NULL;
MENU_HANDLER(ch) = menu_long_string;
ch->desc->max_str = length;
ch->desc->str = return_ptr;
if (PLR_FLAGGED(ch, PLR_EXEDIT))
{
MENU_PROMPT(ch) = NULL;
sprintf(shellfname, "%s.edit", GET_NAME(ch));
startshell(ch->desc, "", shellfname);
}
else
if (cliedit)
{
MENU_PROMPT(ch) = NULL;
}
else
{
send_to_char(prompt, ch);
MENU_PROMPT(ch) = NULL;
}
return 0;
}
// one line text entry
int do_string_arg(chdata *ch, char *prompt, char **return_ptr, char *suffix)
{
struct menu_string_arg *arg;
CREATE(arg, struct menu_string_arg, 1);
menu_push(ch);
MENU_HANDLER_ARG(ch) = (void *) arg;
arg->return_ptr = return_ptr;
arg->suffix = suffix;
MENU_PROMPT(ch) = prompt;
menu_jump(ch, menu_string);
return 0;
}
int toggle_menu(chdata *ch, char *prompt, int *return_ptr, char **strings)
{
int i;
struct menu_toggle_bits_arg *arg;
CREATE(arg, struct menu_toggle_bits_arg, 1);
menu_push(ch);
MENU_HANDLER_ARG(ch) = (void *) arg;
arg->bit_field = return_ptr;
arg->bit_strs = strings;
for (i = 0; *(strings[i]) != '\n'; i++)
;
arg->n_bit_strs = i;
MENU_PROMPT(ch) = prompt;
menu_jump(ch, menu_toggle_bits);
return 0;
}
/* same as toggle_menu but with long referenced */
int toggle_menu_long(chdata *ch, char *prompt, long *return_ptr, char **strings)
{
int i;
struct menu_toggle_bits_long_arg *arg;
CREATE(arg, struct menu_toggle_bits_long_arg, 1);
menu_push(ch);
MENU_HANDLER_ARG(ch) = (void *) arg;
arg->bit_field = return_ptr;
arg->bit_strs = strings;
for (i = 0; *(strings[i]) != '\n'; i++)
;
arg->n_bit_strs = i;
MENU_PROMPT(ch) = prompt;
menu_jump(ch, menu_toggle_bits_long);
return 0;
}
int get_integer_arg(chdata *ch, char *prompt, void *return_ptr,
int return_size, int min_value, int max_value)
{
struct menu_get_integer_arg *arg;
CREATE(arg, struct menu_get_integer_arg, 1);
menu_push(ch);
MENU_HANDLER_ARG(ch) = (void *) arg;
arg->min = min_value;
arg->max = max_value;
arg->size = return_size;
arg->return_ptr = return_ptr;
arg->strings = NULL;
arg->n_strings = 0;
arg->offset = 0;
MENU_PROMPT(ch) = prompt;
menu_jump(ch, menu_get_integer);
return 0;
}
int get_integer_list(chdata *ch, char *prompt, void *return_ptr,
int return_size, char **strings)
{
int i;
struct menu_get_integer_arg *arg;
CREATE(arg, struct menu_get_integer_arg, 1);
menu_push(ch);
MENU_HANDLER_ARG(ch) = (void *) arg;
arg->min = 1;
arg->offset = 1;
arg->size = return_size;
arg->return_ptr = return_ptr;
arg->strings = strings;
for (i = 0; *(strings[i]) != '\n'; i++)
;
arg->n_strings = i;
arg->max = i;
MENU_PROMPT(ch) = prompt;
menu_jump(ch, menu_get_integer);
return 0;
}
// push a menu onto chars stack
int menu_push(chdata *ch)
{
ch->desc->menu_args[MENU_DEPTH(ch)] = MENU_HANDLER_ARG(ch);
ch->desc->menu_stack[MENU_DEPTH(ch)++] = MENU_HANDLER(ch);
return 0;
}
// pop a menu off chars stack
int menu_pop(chdata *ch)
{
MENU_HANDLER_ARG(ch) = ch->desc->menu_args[--MENU_DEPTH(ch)];
MENU_HANDLER(ch) = ch->desc->menu_stack[MENU_DEPTH(ch)];
return 0;
}
// pop menu off, and call menu
int menu_back(chdata *ch)
{
menu_pop(ch);
(*MENU_HANDLER(ch))(ch, NULL);
return 0;
}
ROA_MENU(menu_long_string)
{
menu_back(ch);
}
ROA_MENU(menu_string)
{
struct menu_string_arg *arg = MENU_HANDLER_ARG(ch);
if (input_str)
{
FREENULL(*arg->return_ptr);
CREATE(*arg->return_ptr, char, strlen(input_str) + strlen(arg->suffix) + 1);
strcpy(*arg->return_ptr, input_str);
strcat(*arg->return_ptr, arg->suffix);
FREENULL(MENU_HANDLER_ARG(ch));
menu_back(ch);
}
}
ROA_MENU(menu_toggle_bits)
{
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char *p;
int field;
int i;
struct menu_toggle_bits_arg *arg = MENU_HANDLER_ARG(ch);
int level = GET_LEVEL(ch);
if (!input_str)
{
menu_title_send("Flag Toggle Menu", ch);
for (i = 0; i < arg->n_bit_strs; i++)
{
sprintf(buf, "%2d.) %%5%-20.20s%%0", i + 1, arg->bit_strs[i]);
if (!((i+1) % 3))
strcat(buf, "\n\r");
send_to_char(buf, ch);
}
sprintbit(*arg->bit_field, arg->bit_strs, buf2);
sprintf(buf, "\n\n\r%%6Bits set%%0: %%5%s%%0\n\r", buf2);
send_to_char(buf, ch);
return;
}
strcpy(buf2, input_str);
// while numbers, set corresponding bits
if (!*buf2)
{
FREENULL(MENU_HANDLER_ARG(ch));
menu_pop(ch);
}
else
while (*buf2)
{
half_chop(buf2, buf, buf2);
p = strtok(buf, " \n\r");
if (p)
field = atoi(p);
else
field = 0;
if (!field)
{
FREENULL(MENU_HANDLER_ARG(ch));
menu_pop(ch);
break;
}
else
if (field > 0 && field <= arg->n_bit_strs)
{
switch (*arg->bit_strs[field-1]) {
case '*': // normally non editable
if (level > LEV_IMPL)
*arg->bit_field ^= (1 << (field - 1));
break;
case '+': // aimp+ only
if (level >= LEV_AIMP)
*arg->bit_field ^= (1 << (field - 1));
break;
default: // any builder can edit...
*arg->bit_field ^= (1 << (field - 1));
break;
}
}
}
(*MENU_HANDLER(ch))(ch, NULL);
}
ROA_MENU(menu_toggle_bits_long)
{
char buf[MAX_STRING_LENGTH];
char buf2[MAX_STRING_LENGTH];
char *p;
long field;
int i;
struct menu_toggle_bits_long_arg *arg = MENU_HANDLER_ARG(ch);
int level = GET_LEVEL(ch);
if (!input_str)
{
menu_title_send("Flag Toggle MenuII", ch);
for (i = 0; i < arg->n_bit_strs; i++)
{
sprintf(buf, "%2d.) %%5%-20.20s%%0", i + 1, arg->bit_strs[i]);
if (!((i+1) % 3))
strcat(buf, "\n\r");
send_to_char(buf, ch);
}
sprintbit(*arg->bit_field, arg->bit_strs, buf2);
sprintf(buf, "\n\n\r%%6Bits set%%0: %%5%s%%0\n\r", buf2);
send_to_char(buf, ch);
return;
}
strcpy(buf2, input_str);
// while numbers, set corresponding bits
if (!*buf2)
{
FREENULL(MENU_HANDLER_ARG(ch));
menu_pop(ch);
}
else
while (*buf2)
{
half_chop(buf2, buf, buf2);
p = strtok(buf, " \n\r");
if (p)
field = atoi(p);
else
field = 0;
if (!field)
{
FREENULL(MENU_HANDLER_ARG(ch));
menu_pop(ch);
}
else
if (field > 0 && field <= arg->n_bit_strs)
{
switch (*arg->bit_strs[field-1]) {
case '*': // normally non editable
if (level > LEV_IMPL)
*arg->bit_field ^= ((long long) 1 << (field - 1));
break;
case '+': // aimp+ only
if (level >= LEV_AIMP)
*arg->bit_field ^= ((long long) 1 << (field - 1));
break;
default: // any builder can edit...
*arg->bit_field ^= ((long long) 1 << (field - 1));
break;
}
}
}
(*MENU_HANDLER(ch))(ch, NULL);
}
ROA_MENU(menu_get_integer)
{
struct menu_get_integer_arg *arg = MENU_HANDLER_ARG(ch);
char *p;
int n;
int i;
if (!input_str)
{
menu_title_send("Generic Selection Menu", ch);
for (i = 0; i < arg->n_strings; i++)
{
sprintf(buf, "%2d.) %%5%-21s%%0", i + 1, arg->strings[i]);
if ((i % 3) == 2)
strcat(buf, "\n\r");
send_to_char(buf, ch);
}
send_to_char("\n\r",ch);
}
else
{
p = strtok(input_str, " \n\r");
if (p)
{
n = atoi(p);
if (n < arg->min || n > arg->max)
{
char buf[80];
sprintf(buf, "%%BValue must be in the range %d to %d%%0.\n\r",
arg->min, arg->max);
send_to_char(buf, ch);
return;
}
n -= arg->offset;
switch (arg->size)
{
case 1:
*(char *)arg->return_ptr = n;
break;
case 2:
*(short *)arg->return_ptr = n;
break;
case 4:
*(int *)arg->return_ptr = n;
break;
}
}
FREENULL(MENU_HANDLER_ARG(ch));
menu_back(ch);
}
}
/* for finding exits to void.. RoA*/
ACMD(do_voidlist)
{
rmdata *w;
int zone, rnum;
int i, top, dir;
BOOL found = FALSE;
if (IS_NPC(ch))
return;
one_argument(argument, buf);
if (!*buf || *buf == '.')
zone = world[ch->in_room].zone;
else
zone = real_zone(atoi(buf));
if (zone < 0)
{
send_to_char("Zone does not exist.\n\r",ch);
return;
}
if (!olc_perms(ch, LEV_GOD, zone))
return;
top = zone_table[zone].top;
for (i = zone * 100; i <= top; i++)
{
if (real_room(i) >= 0)
break;
}
if (i > top)
{
send_to_char("No rooms in that zone.\n\r",ch);
return;
}
while (i <= top)
{
if ((rnum = real_room(i)) < 0)
{
i++;
continue;
}
w = &world[rnum];
for (dir=0; dir < 10; dir++)
if (w->dir_option[dir])
if (w->dir_option[dir]->to_room < 1)
{
sprintf(buf, "Room %5d - %s exits to void.\n\r",i, dirs[dir]);
send_to_char(buf, ch);
found = TRUE;
}
if (w->drift_to > 0 && real_room(w->drift_to) < 0)
{
sprintf(buf, "Check room #%d drift to.\n\r",i);
S2C();
found = TRUE;
}
if (w->float_to > 0 && real_room(w->float_to) < 0)
{
sprintf(buf, "Check room #%d float to.\n\r",i);
S2C();
found = TRUE;
}
if (w->drop_to > 0 && real_room(w->drop_to) < 0)
{
sprintf(buf, "Check room #%d drop to.\n\r",i);
S2C();
found = TRUE;
}
if (ROOM_FLAGGED(rnum, ALTERHIT | ALTERMANA | ALTERMOVE) &&
!ROOM_FLAGGED(rnum, DEATH | FLY_DEATH))
{
if ((w->numdice + w->numdice * w->sizedice) / 2 >= 5)
{
sprintf(buf, "Room %5d - Dice exceed max average.\n\r",i);
S2C();
}
}
i++;
}
if (!found)
send_to_char("No void exits / invalid entries found.\n\r",ch);
}