btmux-0.6-rc4/doc/
btmux-0.6-rc4/event/
btmux-0.6-rc4/game/
btmux-0.6-rc4/game/maps/
btmux-0.6-rc4/game/mechs/
btmux-0.6-rc4/game/text/help/
btmux-0.6-rc4/game/text/help/cat_faction/
btmux-0.6-rc4/game/text/help/cat_inform/
btmux-0.6-rc4/game/text/help/cat_misc/
btmux-0.6-rc4/game/text/help/cat_mux/
btmux-0.6-rc4/game/text/help/cat_mux/cat_commands/
btmux-0.6-rc4/game/text/help/cat_mux/cat_functions/
btmux-0.6-rc4/game/text/help/cat_templates/
btmux-0.6-rc4/game/text/wizhelp/
btmux-0.6-rc4/include/
btmux-0.6-rc4/misc/
btmux-0.6-rc4/python/
btmux-0.6-rc4/src/hcode/btech/
btmux-0.6-rc4/tree/
/*
 * macro.c - ported from BattleTech 3056 MUSE 
 */

#include "copyright.h"
#include "config.h"
#include "macro.h"
#include "commac.h"

#include "config.h"
#include "flags.h"
#include "powers.h"
#include "db.h"
#include "alloc.h"

extern dbref match_thing(dbref player, char *name);

MACENT macro_table[] = {
	{(char *) "add", do_add_macro},
	{(char *) "clear", do_clear_macro},
	{(char *) "chmod", do_chmod_macro},
	{(char *) "chown", do_chown_macro},
	{(char *) "create", do_create_macro},
	{(char *) "def", do_def_macro},
	{(char *) "del", do_del_macro},
	{(char *) "name", do_desc_macro},
	{(char *) "chslot", do_edit_macro},
	{(char *) "ex", do_ex_macro},
	{(char *) "gex", do_gex_macro},
	{(char *) "glist", do_list_macro},
	{(char *) "list", do_status_macro},
	{(char *) "undef", do_undef_macro},
	{(char *) NULL, NULL}
};

void init_mactab(void)
{
	MACENT *mp;

	hashinit(&mudstate.macro_htab, 5 * HASH_FACTOR);

	for(mp = macro_table; mp->cmdname; mp++)
		hashadd(mp->cmdname, (int *) mp, &mudstate.macro_htab);
}

int do_macro(dbref player, char *in, char **out)
{
	char *s;
	char *cmd;
	MACENT *mp;
	char *old;

	cmd = in + 1;

	if(!isPlayer(player)) {
		notify(player, "MACRO: Only players may use macros.");
		return 0;
	}
	old = alloc_lbuf("do_macro");

	StringCopy(old, in);

	for(s = cmd; *s && *s != ' '; s++);
	if(*s == ' ')
		*s++ = 0;

	mp = (MACENT *) hashfind(cmd, &mudstate.macro_htab);
	if(mp != NULL) {
		(*(mp->handler)) (player, s);
		free_lbuf(old);
		return 0;
	}
	if((*out = do_process_macro(player, in, s)) != NULL) {
		free_lbuf(old);
		return 1;
	} else {
		StringCopy(in, old);
		free_lbuf(old);
		return 2;				/*
								 * return any value > 1, and command * * *
								 * processing will 
								 */
	}							/*
								 * continue 
								 */
}

void do_list_macro(dbref player, char *s)
{
	int i;
	int notified = 0;
	struct macros *m;
	char *unparse;

	for(i = 0; i < nummacros; i++) {
		m = macros[i];

		if(can_read_macros(player, m)) {
			if(!notified) {
				notify(player,
					   "Num  Description                         Owner                     LRW");
				notified = 1;
			}
			unparse = unparse_object(player, m->player, 0);
			notify_printf(player, "%-4d %-35.35s %-24.24s  %c%c%c", i,
						  m->desc, unparse, m->status & MACRO_L ? 'L' : '-',
						  m->status & MACRO_R ? 'R' : '-',
						  m->status & MACRO_W ? 'W' : '-');
			free_lbuf(unparse);
		}
	}

	if(!notified)
		notify(player, "MACRO: There are no macro sets you can read.");
}

void do_add_macro(dbref player, char *s)
{
	int first;
	int set;
	struct macros *m;
	struct commac *c;
	int i;

	c = get_commac(player);

	first = -1;
	for(i = 0; i < 5 && first < 0; i++)
		if(c->macros[i] == -1)
			first = i;

	if(first < 0) {
		notify(player,
			   "MACRO: Sorry, you already have 5 sets defined on you.");
	} else if(is_number(s)) {
		set = atoi(s);
		if(set >= 0 && set < nummacros) {
			m = macros[set];
			if(can_read_macros(player, m)) {
				c->macros[first] = set;
				notify_printf(player,
							  "MACRO: Macro set %d added in the %d slot.",
							  set, first);
			} else {
				notify(player, "MACRO: Permission denied.");
			}
		} else {
			notify(player, "MACRO: That macro set does not exist.");
			return;
		}
	} else {
		notify(player,
			   "MACRO: What set do you want to add to your macro system?");
	}
}

void do_del_macro(dbref player, char *s)
{
	struct commac *c;
	int set;

	c = get_commac(player);

	if(is_number(s)) {
		set = atoi(s);
		if(set >= 0 && set < 5 && c->macros[set] >= 0) {
			c->macros[set] = -1;
			notify_printf(player, "MACRO: Macro slot %d cleared.", set);
			if(set == c->curmac) {
				c->curmac = -1;
				notify(player,
					   "MACRO: Deleted current slot, resetting to none.");
			}
		} else
			notify(player, "MACRO: That is not a legal macro slot.");
	} else
		notify(player,
			   "MACRO: What set did you want to delete from your macro system?");
}

void do_desc_macro(dbref player, char *s)
{
	struct macros *m;

	m = get_macro_set(player, -1);
	if(m) {
		free(m->desc);
		m->desc = (char *) malloc(strlen(s) + 1);
		StringCopy(m->desc, s);
		notify_printf(player, "MACRO: Current slot description to %s.", s);
	} else
		notify(player, "MACRO: You have no current slot set.");
}

void do_chmod_macro(dbref player, char *s)
{
	struct macros *m;
	int sign;

	m = get_macro_set(player, -1);

	if(m) {
		if((m->player != player) && !Wizard(player)) {
			notify(player, "MACRO: Permission denied.");
			return;
		}
		if(*s == '!') {
			sign = 0;
			s++;
		} else
			sign = 1;

		switch (*s) {
		case 'L':
		case 'l':
			if(sign) {
				m->status |= MACRO_L;
				notify(player,
					   "MACRO: Default Macro Slot is now locked and unwritable.");
			} else {
				m->status &= ~MACRO_L;
				notify(player, "MACRO: Default Macro Slot is now unlocked.");
			}
			break;
		case 'R':
		case 'r':
			if(sign) {
				m->status |= MACRO_R;
				notify(player,
					   "MACRO: Default Macro Slot set to be readable by others");
			} else {
				m->status &= ~MACRO_R;
				notify(player,
					   "MACRO: Default Macro Slot set to be not readable by others");
			}
			break;
		case 'W':
		case 'w':
			if(sign) {
				m->status |= MACRO_W;
				notify(player,
					   "MACRO: Default Macro Slot set to be writable by others");
			} else {
				m->status &= ~MACRO_W;
				notify(player,
					   "MACRO: Default Macro Slot set to be not writable by others");
			}
			break;
		default:
			notify(player,
				   "MACRO: Sorry, unknown mode.  Legal modes are: L R W");
		}
	} else
		notify(player, "MACRO: You have no current slot set.");
}

void do_gex_macro(dbref player, char *s)
{
	struct macros *m;
	int which;
	int i;
	char buffer[LBUF_SIZE];

	if(!s || !*s) {
		notify(player, "MACRO: You need to specify a macro set.");
		return;
	}
	if(is_number(s)) {
		which = atoi(s);
		if((which >= nummacros) || (which < 0) || (nummacros == 0)) {
			notify_printf(player,
						  "MACRO: Illegal Macro Set.  Macros go from 0 to %d.",
						  nummacros - 1);
			return;
		} else
			m = macros[which];
	} else {
		notify(player, "MACRO: I do not see that set here.");
		return;
	}

	if(m && can_read_macros(player, m)) {
		notify_printf(player, "Macro Definitions for %s", m->desc);
		for(i = 0; i < m->nummacros; i++) {
			sprintf(buffer, "  %-5.5s: %s", m->alias + i * 5, m->string[i]);
			notify(player, buffer);
		}
	} else
		notify(player, "MACRO: Permission denied.");

}

void do_edit_macro(dbref player, char *s)
{
	struct commac *c;
	int set;

	c = get_commac(player);

	if(is_number(s)) {
		set = atoi(s);
		if(set >= 0 && set < 5 && GMac(c->macros[set])) {
			c->curmac = set;
			notify_printf(player, "MACRO: Current slot set to %d.", set);
		} else
			notify(player, "MACRO: That is not a legal macro slot.");
	} else
		notify(player, "MACRO: What slot did you want to make current?");
}

void do_status_macro(dbref player, char *s)
{
	int i;
	struct commac *c;
	struct macros *m;
	char *unparse;

	c = get_commac(player);

	notify(player,
		   "#: Num  Description                         Owner                     LRW");
	for(i = 0; i < 5; i++) {
		if(c->macros[i] >= 0)
			if(!(GMac(c->macros[i])))
				notify_printf(player, "%d: INVALID MACRO SET!", i);
			else {
				m = macros[c->macros[i]];
				unparse = unparse_object(player, m->player, 0);
				notify_printf(player,
							  "%d: %-4d %-35.35s %-24.24s  %c%c%c", i,
							  c->macros[i], m->desc, unparse,
							  m->status & MACRO_L ? 'L' : '-',
							  m->status & MACRO_R ? 'R' : '-',
							  m->status & MACRO_W ? 'W' : '-');
				free_lbuf(unparse);
		} else
			notify_printf(player, "%d:", i);
	}
	notify_printf(player, "Current Macro Slot: %d", c->curmac);
}

void do_ex_macro(dbref player, char *s)
{
	struct macros *m;
	int which;
	int i;
	char buffer[LBUF_SIZE];

	if(is_number(s)) {
		which = atoi(s);
		m = get_macro_set(player, which);
	} else
		m = get_macro_set(player, -1);

	if(m) {
		notify_printf(player, "Macro Definitions for %s", m->desc);
		for(i = 0; i < m->nummacros; i++) {
			sprintf(buffer, "  %-5.5s: %s", m->alias + i * 5, m->string[i]);
			notify(player, buffer);
		}
	} else
		notify(player, "MACRO: Illegal macro set to examine.");

}

void do_chown_macro(dbref player, char *cmd)
{
	struct macros *m;
	dbref thing;
	char *unparse;

	m = get_macro_set(player, -1);
	thing = match_thing(player, cmd);

	if(thing == NOTHING) {
		notify(player, "MACRO: I do not see that here.");
		return;
	}
#if 0
	if(!m || !can_write_macros(player, m)) {
		notify(player, "MACRO: Permission denied.");
	}
#endif
	if(!m) {
		notify(player, "MACRO: No current active macro.");
		return;
	}
	if(!Wizard(player)) {
		notify(player, "MACRO: Sorry, command limited to Wizards.");
		return;
	}
	m->player = thing;
	unparse = unparse_object(player, thing, 0);
	notify_printf(player, "MACRO: Macro %s chowned to %s.", m->desc, unparse);
	free_lbuf(unparse);
}

extern void clear_macro_set(int set)
{
	struct macros *m;
	struct commac *c;
	int i, j;

	if(GMac(set)) {
		m = macros[set];
		for(i = 0; i < m->nummacros; i++) {
			free(m->string[i]);
		}
		free(m->alias);
		free(m->string);
		free(m);

		nummacros--;
		for(i = set; i < nummacros; i++)
			macros[i] = macros[i + 1];
		macros[i] = NULL;

	}
	for(i = 0; i < NUM_COMMAC; i++) {
		c = commac_table[i];
		while (c) {
			for(j = 0; j < 5; j++) {
				if(c->macros[j] == set) {
					c->macros[j] = -1;
					if(c->curmac == j)
						c->curmac = -1;
				} else if(c->macros[j] > set) {
					c->macros[j]--;
				}
			}
			c = c->next;
		}
	}
}

void do_clear_macro(dbref player, char *s)
{
	int set;
	struct macros *m;
	struct commac *c;

	c = get_commac(player);

	if(c->curmac == -1) {
		notify(player, "MACRO: You are not currently editing a macro set.");
		return;
	} else if(c->macros[c->curmac] == -1) {
		notify(player, "MACRO: That is not a valid macro set.");
		return;
	}
	set = c->macros[c->curmac];
	m = macros[set];

	if(GMac(set)) {
		if((player != m->player) && !Wizard(player)) {
			notify(player, "MACRO: You may only CLEAR your own macro sets.");
			return;
		} else if((player == m->player) && (m->status & MACRO_L)) {
			notify(player, "MACRO: Sorry, that macro set is locked.");
			return;
		}
	}
	notify_printf(player, "MACRO: Clearing macro set %d: %s.", set,
				  GMac(set) ? m->desc : "Nonexistent");
	clear_macro_set(set);
}

void do_def_macro(dbref player, char *cmd)
{
	int i, j, where;
	struct macros *m;
	char *alias;
	char *s;
	char buffer[LBUF_SIZE];
	char **ns;
	char *na;

	m = get_macro_set(player, -1);

	if(!m) {
		notify(player, "MACRO: No current set.");
		return;
	}
	if(!can_write_macros(player, m)) {
		notify(player, "MACRO: Permission denied.");
		return;
	}
	for(alias = cmd; *alias && *alias == ' '; alias++)
		*alias = 0;

	cmd = alias;
	for(; *cmd && *cmd != ' ' && *cmd != '='; cmd++);
	while (*cmd && *cmd == ' ')
		*cmd++ = '\0';
	if(*cmd != '=') {
		notify(player,
			   "MACRO: You must specify an = in your macro definition");
		return;
	}
	*cmd++ = 0;
	while (*cmd && *cmd == ' ')
		*cmd++ = 0;

	s = cmd;

	if(!*s) {
		notify(player, "MACRO: You must specify a string to substitute for.");
		return;
	} else if(strlen(alias) > 4) {
		notify(player, "MACRO: Please limit aliases to 4 chars or less.");
		return;
	}
	for(j = 0;
		j < m->nummacros && (strcasecmp(alias, m->alias + j * 5) > 0); j++);
	if(j < m->nummacros && !strcasecmp(alias, m->alias + j * 5)) {
		notify(player, "MACRO: That alias is already defined in this set.");
		sprintf(buffer, "%-4.4s:%s", m->alias + j * 5, m->string[j]);
		notify(player, buffer);
		return;
	}
	if(m->nummacros >= m->maxmacros) {
		m->maxmacros += 10;
		na = (char *) malloc(5 * m->maxmacros);
		ns = (char **) malloc(sizeof(char *) * m->maxmacros);

		for(i = 0; i < m->nummacros; i++) {
			StringCopy(na + i * 5, m->alias + i * 5);
			ns[i] = m->string[i];
		}
		free(m->alias);
		free(m->string);
		m->alias = na;
		m->string = ns;
	}
	where = m->nummacros++;
	for(i = where; i > j; i--) {
		StringCopy(m->alias + i * 5, m->alias + (i - 1) * 5);
		m->string[i] = m->string[i - 1];
	}

	where = j;
	StringCopy(m->alias + where * 5, alias);
	m->string[where] = (char *) malloc(strlen(s) + 1);
	StringCopy(m->string[where], s);
	sprintf(buffer, "MACRO: Macro %s:%s defined.", alias, s);
	notify(player, buffer);
}

void do_undef_macro(dbref player, char *cmd)
{
	int i;
	struct macros *m;

	m = get_macro_set(player, -1);

	if(!m || !can_write_macros(player, m)) {
		notify(player, "MACRO: Permission denied.");
		return;
	}
	for(i = 0; i < m->nummacros; i++) {
		if(!strcmp(m->alias + i * 5, cmd)) {
			free(m->string[i]);
			m->nummacros--;
			for(; i < m->nummacros; i++) {
				StringCopy(m->alias + i * 5, m->alias + i * 5 + 5);
				m->string[i] = m->string[i + 1];
			}
			notify(player, "MACRO: Macro deleted from set.");
			return;
		}
	}
	notify(player, "MACRO: That macro is not in this set.");
}

char *do_process_macro(dbref player, char *in, char *s)
{
	char *cmd;
	char *tar;
	char *next;
	struct macros *m;
	int first, last, current = 0;
	int dir;
	int i;
	struct commac *c;
	char *buff;

	c = get_commac(player);
	buff = alloc_lbuf("do_process_macro");
	cmd = in + 1;
	buff[0] = '\0';				/*
								 * End the string 
								 */
	for(i = 0; i < 5; i++) {
		if(GMac(c->macros[i])) {
			m = macros[c->macros[i]];
			if(m->nummacros > 0) {
				first = 0;
				last = m->nummacros - 1;
				dir = 1;
				next = in + 1;
				while (dir && (first <= last)) {
					current = (first + last) / 2;
					dir = strcmp(next, m->alias + 5 * current);
					if(dir < 0)
						last = current - 1;
					else
						first = current + 1;
				}

				if(!dir) {
					tar = m->string[current];
#if 1							/* Original MUSE code */
					next = buff;
					while (*tar) {
						if(*tar == '%' && *(tar + 1) == '*') {
							*next++ = '*';
							tar += 2;
						} else if(*tar == '*') {
							*next = 0;
							strcat(next, s);
							tar++;
							next += strlen(next);
						} else
							*next++ = *tar++;
					}
					*next = 0;
#else
					while (*tar) {
						switch (*tar) {
						case '*':
							if(!buff)
								StringCopy(buff, s);
							else
								strcat(buff, s);
							break;
						case '%':
							if(!buff)
								StringCopy(buff, tar + 1);
							else
								sprintf(buff, "%s%c", buff, tar + 1);
							*tar++;
							break;
						default:
							if(!buff)
								StringCopy(buff, tar);
							else
								sprintf(buff, "%s%c", buff, *tar);
							break;
						}
						*tar++;
					}
#endif
					return buff;
				}
			}
		}
	}
	free_lbuf(buff);
	return NULL;
}

struct macros *get_macro_set(dbref player, int which)
{
	int set;
	struct commac *c;

	c = get_commac(player);

	if(c) {
		set = -1;
		if(which >= 0 && which < 5)
			set = c->macros[which];
		else if(c->curmac >= 0)
			set = c->macros[c->curmac];

		if(set == -1)
			return NULL;
		else
			return macros[set];
	} else
		return NULL;
}

void do_sort_macro_set(struct macros *m)
{
	int i;
	int cont;
	char buffer[10];
	char *s;

	cont = 1;
	while (cont) {
		cont = 0;
		for(i = 0; i < m->nummacros - 1; i++)
			if(strcasecmp(m->alias + i * 5, m->alias + (i + 1) * 5) > 0) {
				StringCopy(buffer, m->alias + i * 5);
				StringCopy(m->alias + i * 5, m->alias + (i + 1) * 5);
				StringCopy(m->alias + (i + 1) * 5, buffer);
				s = m->string[i];
				m->string[i] = m->string[i + 1];
				m->string[i + 1] = s;
				cont = 1;
			}
	}
}

void do_create_macro(dbref player, char *s)
{
	int first;
	int i;
	struct commac *c;
	struct macros **nm;
	int set;

	c = get_commac(player);
	first = -1;
	for(i = 0; i < 5 && first < 0; i++)
		if(c->macros[i] == -1)
			first = i;
	if(first < 0) {
		notify(player,
			   "MACRO: Sorry, you already have 5 sets defined on you.");
		return;
	}
	if(nummacros >= maxmacros) {
		maxmacros += 10;
		nm = (struct macros **) malloc(sizeof(struct macros *) * maxmacros);

		for(i = 0; i < nummacros; i++)
			nm[i] = macros[i];
		free(macros);
		macros = nm;
	}
	set = nummacros++;
	macros[set] = (struct macros *) malloc(sizeof(struct macros));

	macros[set]->player = player;
	macros[set]->status = 0;
	macros[set]->nummacros = 0;
	macros[set]->maxmacros = 0;
	macros[set]->alias = NULL;
	macros[set]->string = NULL;
	macros[set]->desc = (char *) malloc(strlen(s) + 1);
	StringCopy(macros[set]->desc, s);
	c->curmac = first;
	c->macros[first] = set;

	notify_printf(player,
				  "MACRO: Macro set %d created with description %s.", set, s);
}

int can_write_macros(dbref player, struct macros *m)
{
	if(m->status & MACRO_L)
		return 0;

	if(m->player == player)
		return 1;
	else
		return m->status & MACRO_W;
}

int can_read_macros(dbref player, struct macros *m)
{
	if(Wizard(player))
		return 1;

	if(!m)
		return 0;

	if(m->player == player)
		return 1;
	else
		return m->status & MACRO_R;
}

#define TST(cmd,msg) if (cmd) { fprintf(stderr, msg); exit(1); }

void load_macros(FILE * fp)
{
	int i, j;
	char *c;
	char *t;
	char buffer[LBUF_SIZE];
	struct macros *m;

	TST(fscanf(fp, "%d\n", &nummacros) != 1, "Error: Loading #macros\n");
	maxmacros = nummacros;

	if(maxmacros > 0)
		macros =
			(struct macros **) malloc(sizeof(struct macros *) * nummacros);
	else
		macros = NULL;

	for(i = 0; i < nummacros; i++) {
		macros[i] = (struct macros *) malloc(sizeof(struct macros));

		m = macros[i];

		fgets(buffer, LBUF_SIZE, fp);
		TST(sscanf(buffer, "%d %d %d\n", &(m->player), &(m->nummacros), &j)
			!= 3, tprintf("Reading macro set #%d\n", i));
		m->status = j;

		fgets(buffer, LBUF_SIZE, fp);
		if(*buffer)
			if(buffer[strlen(buffer) - 1] == '\n')
				buffer[strlen(buffer) - 1] = 0;

		m->desc = (char *) malloc(strlen(buffer) - 1);
		StringCopy(m->desc, buffer + 2);

		m->maxmacros = m->nummacros;
		if(m->nummacros > 0) {
			m->alias = (char *) malloc(5 * m->maxmacros);
			m->string = (char **) malloc(sizeof(char *) * m->nummacros);

			for(j = 0; j < m->nummacros; j++) {
				t = m->alias + j * 5;
				fgets(buffer, LBUF_SIZE, fp);
				if(buffer[strlen(buffer) - 1] == '\n')
					buffer[strlen(buffer) - 1] = 0;
				for(c = buffer; *c && *c != ' '; c++);
				*c = 0;
				if(strlen(buffer) > 4) {
					fprintf(stderr, "Error reading macro set #%d!\n", i);
					exit(1);
				}
				if(!*buffer) {

/* fprintf(stderr, "Error in macro set #%d (macro %d) : Invalid macro name.\n", i, j); */
					t[0] = 0;
				} else
					strcpy(t, buffer);
				c++;
				m->string[j] = (char *) malloc(strlen(c) + 1);
				StringCopy(m->string[j], c);
			}
			do_sort_macro_set(m);
		} else {
			m->alias = NULL;
			m->string = NULL;
		}
	}
	while (1) {
		for(i = 0; i < nummacros; i++)
			if(!isPlayer(macros[i]->player))
				break;
		if(i >= nummacros)
			break;
		clear_macro_set(i);
	}
}

void save_macros(FILE * fp)
{
	int i, j;
	struct macros *m;

	fprintf(fp, "%d\n", nummacros);

	for(i = 0; i < nummacros; i++) {
		m = macros[i];
		fprintf(fp, "%d %d %d\n", m->player, m->nummacros, (int) m->status);
		fprintf(fp, "D:%s\n", m->desc);
		for(j = 0; j < m->nummacros; j++)
			fprintf(fp, "%s %s\n", m->alias + j * 5, m->string[j]);
	}
}