btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * $Id: mechrep.c,v 1.5 2005/07/02 19:02:23 av1-op Exp $
 *
 * Last modified: Thu Aug 13 23:41:12 1998 fingon
 * Copyright (c) 1999-2005 Kevin Stevens
 *   All right reserved
 */

#include "config.h"

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/file.h>
#include <dirent.h>
#include <sys/stat.h>

#define MECH_STAT_C		/* want to use the POSIX stat() call. */

#include "externs.h"
#include "mech.h"
#include "mechrep.h"
#include "create.h"
#include "p.mech.build.h"
#include "p.mech.status.h"
#include "p.template.h"
#include "p.mechrep.h"
#include "p.mech.restrict.h"
#include "p.mech.consistency.h"
#include "p.mech.utils.h"
#include "mech.events.h"

/* Selectors */
#define SPECIAL_FREE 0
#define SPECIAL_ALLOC 1

extern char *strtok(char *s, const char *ct);

/* EXTERNS THAT SHOULDN'T BE IN HERE! */
extern void *FindObjectsData(dbref key);
dbref match_thing(dbref player, char *name);
void muxevent_remove_data(void *data);

#define MECHREP_COMMON(a) \
struct mechrep_data *rep = (struct mechrep_data *) data; \
MECH *mech; \
DOCHECK(!Template(player), "I'm sorry Dave, can't do that."); \
if (!CheckData(player, rep)) return; \
if (a) { DOCHECK(rep->current_target == -1, "You must set a target first!"); \
mech = getMech (rep->current_target); \
if (!CheckData(player, mech)) return; }

/*--------------------------------------------------------------------------*/

/* Code Begins                                                              */

/*--------------------------------------------------------------------------*/

/* Alloc free function */

/* Alloc/free routine */

void newfreemechrep(dbref key, void **data, int selector)
{
    struct mechrep_data *new = *data;

    switch (selector) {
    case SPECIAL_ALLOC:
	new->current_target = -1;
	break;
    }
}

/* With cap R means restricted command */

void mechrep_Rresetcrits(dbref player, void *data, char *buffer)
{
    int i;

    MECHREP_COMMON(1);
    notify(player, "Default criticals set!");
    for (i = 0; i < NUM_SECTIONS; i++)
	FillDefaultCriticals(mech, i);
}

void mechrep_Rdisplaysection(dbref player, void *data, char *buffer)
{
    char *args[1];
    int index;

    MECHREP_COMMON(1);
    DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
	"You must specify a section to list the criticals for!");
    index =
	ArmorSectionFromString(MechType(mech), MechMove(mech), args[0]);
    DOCHECK(index == -1, "Invalid section!");
    CriticalStatus(player, mech, index);
}

#define MechComputersRadioRange(mech) \
(DEFAULT_RADIORANGE * generic_radio_multiplier(mech))

void mechrep_Rsetradio(dbref player, void *data, char *buffer)
{
    char *args[2];
    int i;

    MECHREP_COMMON(1);
    switch (mech_parseattributes(buffer, args, 2)) {
    case 0:
	notify(player,
	    "This remains to be done [showing of stuff when no args]");
	return;
    case 2:
	notify(player, "Too many args, unable to cope().");
	return;
    }
    i = BOUNDED(1, atoi(args[0]), 5);
    notify(player, tprintf("Radio level set to %d.", i));
    MechRadio(mech) = i;
    MechRadioType(mech) = generic_radio_type(MechRadio(mech), 0);
    notify(player, tprintf("Number of freqs: %d  Extra stuff: %d",
	    MechRadioType(mech) % 16, (MechRadioType(mech) / 16) * 16));
    MechRadioRange(mech) = MechComputersRadioRange(mech);
    notify(player, tprintf("Radio range set to %d.",
	    (int) MechRadioRange(mech)));
}

void mechrep_Rsettarget(dbref player, void *data, char *buffer)
{
    char *args[2];
    int newmech;

    MECHREP_COMMON(0);
    switch (mech_parseattributes(buffer, args, 2)) {
    case 1:
	newmech = match_thing(player, args[0]);
	DOCHECK(!(Good_obj(newmech) &&
		Hardcode(newmech)),
	    "That is not a BattleMech or Vehicle!");
	rep->current_target = newmech;
	notify(player, tprintf("Mech to repair changed to #%d", newmech));
	break;
    default:
	notify(player, "Too many arguments!");
    }
}

void mechrep_Rsettype(dbref player, void *data, char *buffer)
{
    char *args[1];

    MECHREP_COMMON(1);
    DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
	"Invalid number of arguments!");
    switch (toupper(args[0][0])) {
    case 'M':
	MechType(mech) = CLASS_MECH;
	MechMove(mech) = MOVE_BIPED;
	notify(player, "Type set to MECH");
	break;
    case 'Q':
	MechType(mech) = CLASS_MECH;
	MechMove(mech) = MOVE_QUAD;
	notify(player, "Type set to QUAD");
	break;
    case 'G':
	MechType(mech) = CLASS_VEH_GROUND;
	notify(player, "Type set to VEHICLE");
	break;
    case 'V':
	MechType(mech) = CLASS_VTOL;
	MechMove(mech) = MOVE_VTOL;
	notify(player, "Type set to VTOL");
	break;
    case 'N':
	MechType(mech) = CLASS_VEH_NAVAL;
	notify(player, "Type set to NAVAL");
	break;
    case 'A':
	MechType(mech) = CLASS_AERO;
	MechMove(mech) = MOVE_FLY;
	notify(player, "Type set to AeroSpace");
	break;
    case 'D':
	MechType(mech) = CLASS_DS;
	MechMove(mech) = MOVE_FLY;
	notify(player, "Type set to DropShip");
	break;
    case 'S':
	MechType(mech) = CLASS_SPHEROID_DS;
	MechMove(mech) = MOVE_FLY;
	notify(player, "Type set to SpheroidDropship");
	break;
    case 'B':
    	MechType(mech) = CLASS_BSUIT;
    	MechMove(mech) = MOVE_BIPED;
    	notify(player, "Type set to BattleSuit");
    	break;
    default:
	notify(player,
	    "Types are: MECH, GROUND, VTOL, NAVAL, AERO, DROPSHIP and SPHEROIDDROPSHIP");
	break;
    }
}

#define SETVALUE_FUNCTION_FLOAT(funcname,valname,valstring,modifier) \
void funcname (dbref player, void *data, char *buffer) \
{ char *args[1]; float f; MECHREP_COMMON(1); \
  DOCHECK(mech_parseattributes (buffer, args, 1) != 1, \
	  tprintf("Invalid number of arguments to Set%s!", valstring)); \
  f = atof(args[0]); \
  valname = f * modifier; \
  notify(player, tprintf("%s changed to %.2f.", valstring, valname)); \
}


#define SETVALUE_FUNCTION_INT(funcname,valname,valstring,modifier) \
void funcname (dbref player, void *data, char *buffer) \
{ char *args[1]; int f; MECHREP_COMMON(1); \
  DOCHECK(mech_parseattributes (buffer, args, 1) != 1, \
	  tprintf("Invalid number of arguments to Set%s!", valstring)); \
  f = atoi(args[0]); \
  valname = f * modifier; \
  notify(player, tprintf("%s changed to %d.", valstring, valname)); \
}

SETVALUE_FUNCTION_FLOAT(mechrep_Rsetspeed, MechMaxSpeed(mech), "Maxspeed",
    KPH_PER_MP);
SETVALUE_FUNCTION_FLOAT(mechrep_Rsetjumpspeed, MechJumpSpeed(mech),
    "Jumpspeed", KPH_PER_MP);
SETVALUE_FUNCTION_INT(mechrep_Rsetheatsinks, MechRealNumsinks(mech),
    "Heatsinks", 1);
SETVALUE_FUNCTION_INT(mechrep_Rsetlrsrange, MechLRSRange(mech), "LRSrange",
    1);
SETVALUE_FUNCTION_INT(mechrep_Rsettacrange, MechTacRange(mech), "TACrange",
    1);
SETVALUE_FUNCTION_INT(mechrep_Rsetscanrange, MechScanRange(mech),
    "SCANrange", 1);
SETVALUE_FUNCTION_INT(mechrep_Rsetradiorange, MechRadioRange(mech),
    "RADIOrange", 1);
SETVALUE_FUNCTION_INT(mechrep_Rsettons, MechTons(mech), "Tons", 1);


void mechrep_Rsetmove(dbref player, void *data, char *buffer)
{
    char *args[1];

    MECHREP_COMMON(1);
    DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
	"Invalid number of arguments!");
    switch (toupper(args[0][0])) {
    case 'T':
	MechMove(mech) = MOVE_TRACK;
	notify(player, "Movement set to TRACKED");
	break;
    case 'W':
	MechMove(mech) = MOVE_WHEEL;
	notify(player, "Movement set to WHEELED");
	break;
    case 'H':
	switch (toupper(args[0][1])) {
	case 'O':
	    MechMove(mech) = MOVE_HOVER;
	    notify(player, "Movement set to HOVER");
	    break;
	case 'U':
	    MechMove(mech) = MOVE_HULL;
	    notify(player, "Movement set to HULL");
	    break;
	}
	break;
    case 'V':
	MechMove(mech) = MOVE_VTOL;
	notify(player, "Movement set to VTOL");
	break;
    case 'Q':
	MechMove(mech) = MOVE_QUAD;
	notify(player, "Movement set to QUAD");
	break;
    case 'S':
	MechMove(mech) = MOVE_SUB;
	notify(player, "Movement set to SUB");
	break;
    case 'F':
	switch (toupper(args[0][1])) {
	case 'O':
	    MechMove(mech) = MOVE_FOIL;
	    notify(player, "Movement set to FOIL");
	    break;
	case 'L':
	    MechMove(mech) = MOVE_FLY;
	    notify(player, "Movement set to FLY");
	    break;
	}
    case 'N':
    	MechMove(mech) = MOVE_NONE;
    	notify(player, "Movement set to NONE");
    	break;
    default:
	notify(player,
	    "Types are: TRACK, WHEEL, VTOL, HOVER, HULL, FLY, SUB, FOIL and NONE");
	break;
    }
}

/*
 * Implement a name cache of a template names.  This allows differences
 * in case and characters past the 14th to be ignored in mech references
 * when loading templates.  Templates can also be stored in any subdirectory
 * of the main template directory instead of in just one of list of hard
 * coded subdirectories.  
 * 
 * CACHE_MAXNAME sets the limit on how long a template filename can be.
 * Any template with a filename longer than this is ignored and not stored
 * in the cache.
 *
 * MECH_MAXREF sets the number of signficant characters in a mechref when
 * searching the cache.  This should be equal to the length of the
 * 'mech_type' (minus one for the terminating '\0' character) field of
 * MECH structure.
 * 
 */

enum {
    CACHE_MAXNAME = 24,
    MECH_MAXREF = 14
};

struct tmpldirent {
    char name[CACHE_MAXNAME + 1];
    char const *dir;
};

struct tmpldir {
    char name[CACHE_MAXNAME + 1];
    struct tmpldir *next;
};

struct tmpldirent *tmpl_list = NULL;
int tmpl_pos = 0;
int tmpl_len = 0;

struct tmpldir *tmpldir_list = NULL;

/*
 * The ordering function for the template name cache.  Used to sort and
 * search the cache.
 */
static int tmplcmp(void const *v1, void const *v2)
{
    struct tmpldirent const *p1 = v1;
    struct tmpldirent const *p2 = v2;

    return strncasecmp(p1->name, p2->name, MECH_MAXREF);
}

/*
 * Add all the template names in a directory to the template cache.
 */
static int scan_template_dir(char const *dirname, char const *parent)
{
    char buf[1000];
    int dirnamelen = strlen(dirname);
    DIR *dir = opendir(dirname);

    if (dir == NULL) {
	return -1;
    }

    while (1) {
	struct stat sb;
	struct dirent *ent = readdir(dir);

	if (ent == NULL) {
	    break;
	}

	if (dirnamelen + 1 + strlen(ent->d_name) + 1 > sizeof buf) {
	    continue;
	}

	sprintf(buf, "%s/%s", dirname, ent->d_name);
	if (stat(buf, &sb) == -1) {
	    continue;
	}

	if (parent == NULL && S_ISDIR(sb.st_mode)
	    && ent->d_name[0] != '.' &&
	    strlen(ent->d_name) <= CACHE_MAXNAME) {
	    struct tmpldir *link;

	    Create(link, struct tmpldir, 1);

	    strcpy(link->name, ent->d_name);
	    link->next = tmpldir_list;
	    tmpldir_list = link;
	    continue;
	}

	if (!S_ISREG(sb.st_mode)) {
	    continue;
	}

	if (tmpl_pos == tmpl_len) {
	    if (tmpl_len == 0) {
		tmpl_len = 4;
		Create(tmpl_list, struct tmpldirent, tmpl_len);
	    } else {
		tmpl_len *= 2;
		ReCreate(tmpl_list, struct tmpldirent, tmpl_len);
	    }
	}

	strncpy(tmpl_list[tmpl_pos].name, ent->d_name, CACHE_MAXNAME);
	tmpl_list[tmpl_pos].name[CACHE_MAXNAME] = '\0';
	tmpl_list[tmpl_pos].dir = parent;
	tmpl_pos++;
    }

    closedir(dir);
    return 0;
}

/*
 * Scan all the template names in the mech template directory.  Only looks
 * in the mech template directory and it immediate subdirectories. 
 * It doesn't recursively look any further down the tree.
 */

static int scan_templates(char const *dir)
{
    char buf[1000];
    struct tmpldir *p;

    if (scan_template_dir(dir, NULL) == -1) {
	return -1;
    }

    p = tmpldir_list;
    while (p != NULL) {
	sprintf(buf, "%s/%s", dir, p->name);
	scan_template_dir(buf, p->name);
	p = p->next;
    }

    qsort(tmpl_list, tmpl_pos, sizeof tmpl_list[0], tmplcmp);

    return 0;
}

/*
 * Free all the memory used by the template cache.  Sets the cache to
 * the empty state.
 */
static void free_template_list()
{
    struct tmpldir *p;

    free(tmpl_list);

    p = tmpldir_list;
    while (p != NULL) {
	struct tmpldir *np = p->next;

	free(p);
	p = np;
    }

    tmpl_list = NULL;
    tmpldir_list = NULL;
    tmpl_pos = 0;
    tmpl_len = 0;

    return;
}

char *subdirs[] = {
    "3025",
    "3050",
    "3055",
    "3058",
    "3060",
    "2750",
    "Aero",
    "MISC",
    "Clan",
    "ClanVehicles",
    "Clan2nd",
    "ClanAero",
    "Custom",
    "Solaris",
    "Vehicles",
    "MFNA",
    "Infantry",
    NULL
};

void mechrep_Rloadnew(dbref player, void *data, char *buffer)
{
    char *args[1];

    MECHREP_COMMON(1);
    if (mech_parseattributes(buffer, args, 1) == 1)
	if (mech_loadnew(player, mech, args[0]) == 1) {
	    muxevent_remove_data((void *) mech);
	    clear_mech_from_LOS(mech);
	    notify(player, "Template loaded.");
	    return;
	}
    notify(player, "Unable to read that template.");
}

void clear_mech(MECH * mech, int flag)
{
    int i, j;

    mech->brief = 1;

    bzero(&mech->rd, sizeof(mech_rd));
    bzero(&mech->ud, sizeof(mech_ud));

    MechSpotter(mech) = -1;
    MechTarget(mech) = -1;
    MechChargeTarget(mech) = -1;
    MechChargeTimer(mech) = 0;
    MechChargeDistance(mech) = 0;
    MechSwarmTarget(mech) = -1;
    MechDFATarget(mech) = -1;
    MechTargX(mech) = -1;
    MechStatus(mech) = 0;
    MechTargY(mech) = -1;
    MechPilot(mech) = -1;
    MechAim(mech) = NUM_SECTIONS;
    StopBurning(mech);
    if (flag) {
	for (i = 0; i < NUM_TICS; i++)
	    for (j = 0; j < TICLONGS; j++)
		mech->tic[i][j] = 0;
	for (i = 0; i < FREQS; i++) {
	    mech->freq[i] = 0;
	    mech->freqmodes[i] = 0;
	    mech->chantitle[i][0] = 0;
	}
    }
}

char *mechref_path(char *id)
{
    static char openfile[1024];
    FILE *fp;
    int i = 0;			/* this int has double use... ugly, but effective */

    /*
     * If the template name doesn't have slash search for it in the
     * template name cache.
     */
  redo:
    if (strchr(id, '/') == NULL && (tmpl_list != NULL ||
	    scan_templates(MECH_PATH) != -1)) {
	struct tmpldirent *ent;
	struct tmpldirent key;

	strncpy(key.name, id, CACHE_MAXNAME);
	key.name[CACHE_MAXNAME] = '\0';

	ent =
	    bsearch(&key, tmpl_list, tmpl_pos, sizeof tmpl_list[0],
	    tmplcmp);
	if (ent == NULL) {
	    return NULL;
	}
	if (ent->dir == NULL) {
	    sprintf(openfile, "%s/%s", MECH_PATH, ent->name);
	} else {
	    sprintf(openfile, "%s/%s/%s", MECH_PATH, ent->dir, ent->name);
	}
	if (access(openfile, R_OK) != 0) {
	    /* The file is missing (or unreadable)
	       invalidate the cache and try again,
	       if *that* fails, fall back to the old version. */
	    if (!i) {
		i = 1;
		free_template_list();
		goto redo;
	    } else
		goto oldstyle;
	}
	return openfile;
    }
  oldstyle:
    /*
     * Look up a template name the old way...
     */
    sprintf(openfile, "%s/%s", MECH_PATH, id);
    fp = fopen(openfile, "r");
    for (i = 0; !fp && subdirs[i]; i++) {
	sprintf(openfile, "%s/%s/%s", MECH_PATH, subdirs[i], id);
	fp = fopen(openfile, "r");
    }
    if (fp) {
	fclose(fp);
	return openfile;
    }
    return NULL;
}

int load_mechdata2(dbref player, MECH * mech, char *id)
{
    FILE *fp = NULL;
    char *filename;

    filename = mechref_path(id);

    if (!filename)
	return 0;
    if (!(fp = fopen(filename, "r")))
	return 0;
    fclose(fp);
    return load_template(player, mech, filename) >= 0 ? 1 : 0;
}

extern int num_def_weapons;

int unable_to_find_proper_type(int i)
{
    if (!i)
	return 0;
    if (IsWeapon(i)) {
	if (i > (num_def_weapons))
	    return 1;
    }
    if (IsAmmo(i)) {
	if ((Ammo2Weapon(i) + 1) > (num_def_weapons))
	    return 1;
    }
    if (IsSpecial(i))
	if (Special2I(i) >= count_special_items())
	    return 1;
    return 0;
}

int load_mechdata(MECH * mech, char *id)
{
    FILE *fp = NULL;
    int i, j, k, t;
    int i1, i2, i3, i4, i5, i6;
    char *filename;

    filename = mechref_path(id);
    TEMPLATE_GERR(filename == NULL, tprintf("No matching file for '%s'.",
	    id));
    if (filename)
	fp = fopen(filename, "r");
    TEMPLATE_GERR(!fp, tprintf("Unable to open file %s (%s)!", filename,
	    id));
    strncpy(MechType_Ref(mech), id, 15);
    MechType_Ref(mech)[14] = '\0';
    TEMPLATE_GERR(fscanf(fp, "%d %d %d %d %d %f %f %d\n", &i1, &i2, &i3,
	    &i4, &i5, &MechMaxSpeed(mech), &MechJumpSpeed(mech), &i6) < 8,
	"Old template loading system: %s is invalid template file.", id);
    MechTons(mech) = i1;
    MechTacRange(mech) = i2;
    MechLRSRange(mech) = i3;
    MechScanRange(mech) = i4;
    MechRealNumsinks(mech) = i5;
#define DROP(a) \
  if (i6 & a) i6 &= ~a
    DROP(32768);		/* Quad */
    DROP(16384);		/* Salvagetech */
    DROP(8192);			/* Cargotech */
    DROP(4196);			/* Watergun */
    MechSpecials(mech) = i6;
    for (k = 0; k < NUM_SECTIONS; k++) {
	i = k;
	if (MechType(mech) == 4) {
	    switch (k) {
	    case 3:
		i = 4;
		break;
	    case 4:
		i = 5;
		break;
	    case 5:
		i = 3;
		break;
	    }
	}
	TEMPLATE_GERR(fscanf(fp, "%d %d %d %d\n", &i1, &i2, &i3, &i4) < 4,
	    "Insufficient data reading section %d!", i);
	MechSections(mech)[i].recycle = 0;
	SetSectArmor(mech, i, i1);
	SetSectOArmor(mech, i, i1);
	SetSectInt(mech, i, i2);
	SetSectOInt(mech, i, i2);
	SetSectRArmor(mech, i, i3);
	SetSectORArmor(mech, i, i3);
	/* Remove all rampant AXEs from the arms themselves, we do
	   things differently here */
	if (i4 & 4)
	    i4 &= ~4;
	MechSections(mech)[i].config = i4;
	for (j = 0; j < NUM_CRITICALS; j++) {
	    TEMPLATE_GERR(fscanf(fp, "%d %d %d\n", &i1, &i2, &i3) < 3,
		"Insufficient data reading critical %d/%d!", i, j);
	    MechSections(mech)[i].criticals[j].type = i1;
	    TEMPLATE_GERR(unable_to_find_proper_type(GetPartType(mech, i,
			j)), "Invalid datatype at %d/%d!", i, j);
	    if (IsSpecial(i1))
		i1 += SPECIAL_BASE_INDEX - OSPECIAL_BASE_INDEX;
	    if (IsWeapon(GetPartType(mech, i, j)) &&
		IsAMS((t = Weapon2I(GetPartType(mech, i, j))))) {
		if (MechWeapons[t].special & CLAT)
		    MechSpecials(mech) |= CL_ANTI_MISSILE_TECH;
		else
		    MechSpecials(mech) |= IS_ANTI_MISSILE_TECH;
	    }
	    MechSections(mech)[i].criticals[j].data = i2;
	    MechSections(mech)[i].criticals[j].firemode = i3;
	}
    }
    if (fscanf(fp, "%d %d\n", &i1, &i2) == 2) {
	MechType(mech) = i1;
	TEMPLATE_GERR(MechType(mech) > CLASS_LAST, "Invalid 'mech type!");
	MechMove(mech) = i2;
	TEMPLATE_GERR(MechMove(mech) > MOVENEMENT_LAST,
	    "Invalid movenement type!");
    }
    if (fscanf(fp, "%d\n", &i1) != 1)
	MechRadioRange(mech) = DEFAULT_RADIORANGE;
    else
	MechRadioRange(mech) = i1;
    fclose(fp);
    return 1;
}

#undef  LOADNEW_LOADS_OLD_IF_FAIL
#define LOADNEW_LOADS_MUSE_FORMAT

int mech_loadnew(dbref player, MECH * mech, char *id)
{
    char mech_origid[100];

    strncpy(mech_origid, MechType_Ref(mech), 99);
    mech_origid[99] = '\0';

    if (!strcmp(mech_origid, id)) {
	clear_mech(mech, 0);
	if (load_mechdata2(player, mech, id) <= 0)
	    return load_mechdata(mech, id) > 0;
	return 1;
    } else {
	clear_mech(mech, 1);
	if (load_mechdata2(player, mech, id) < 1)
#ifdef LOADNEW_LOADS_MUSE_FORMAT
	    if (load_mechdata(mech, id) < 1)
#endif
#ifdef LOADNEW_LOADS_OLD_IF_FAIL
		if (load_mechdata2(player, mech, mech_origid) < 1)
#ifdef LOADNEW_LOADS_MUSE_FORMAT
		    if (load_mechdata(mech, mech_origid) < 1)
#endif
#endif
			return 0;
    }
    return 1;
}

void mechrep_Rrestore(dbref player, void *data, char *buffer)
{
    char *c;

    MECHREP_COMMON(1);
    c = silly_atr_get(mech->mynum, A_MECHREF);
    DOCHECK(!c || !*c, "Sorry, I don't know what type of mech this is");
    DOCHECK(mech_loadnew(player, mech, c) == 1, "Restoration complete!");
    notify(player, "Unable to restore this mech!.");
}

void mechrep_Rsavetemp(dbref player, void *data, char *buffer)
{
    char *args[1];
    FILE *fp;
    char openfile[512];
    int i, j;

    MECHREP_COMMON(1);

    free_template_list();

    DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
	"You must specify a template name!");
    DOCHECK(strstr(args[0], "/"), "Invalid file name!");
    notify(player, tprintf("Saving %s", args[0]));
    sprintf(openfile, "%s/", MECH_PATH);
    strcat(openfile, args[0]);
    DOCHECK(!(fp =
	    fopen(openfile, "w")),
	"Unable to open/create mech file! Sorry.");
    fprintf(fp, "%d %d %d %d %d %.2f %.2f %d\n", MechTons(mech),
	MechTacRange(mech), MechLRSRange(mech), MechScanRange(mech),
	MechRealNumsinks(mech), MechMaxSpeed(mech), MechJumpSpeed(mech),
	MechSpecials(mech));
    for (i = 0; i < NUM_SECTIONS; i++) {
	fprintf(fp, "%d %d %d %d\n", GetSectArmor(mech, i),
	    GetSectInt(mech, i), GetSectRArmor(mech, i),
	    MechSections(mech)[i].config);
	for (j = 0; j < NUM_CRITICALS; j++) {
	    fprintf(fp, "%d %d %d\n",
		MechSections(mech)[i].criticals[j].type,
		MechSections(mech)[i].criticals[j].data,
		MechSections(mech)[i].criticals[j].firemode);
	}
    }
    fprintf(fp, "%d %d\n", MechType(mech), MechMove(mech));
    fprintf(fp, "%d\n", MechRadioRange(mech));
    fclose(fp);
    notify(player, "Saving complete!");
}

void mechrep_Rsavetemp2(dbref player, void *data, char *buffer)
{
    char *args[1];
    char openfile[512];

    MECHREP_COMMON(1);

    free_template_list();

    DOCHECK(mech_parseattributes(buffer, args, 1) != 1,
	"You must specify a template name!");
    DOCHECK(strstr(args[0], "/"), "Invalid file name!");
    notify(player, tprintf("Saving %s", args[0]));
    sprintf(openfile, "%s/", MECH_PATH);
    strcat(openfile, args[0]);
    DOCHECK(mech_weight_sub(GOD, mech, -1) > (MechTons(mech) * 1024),
	"Error saving template: Too heavy.");
    DOCHECK(save_template(player, mech, args[0], openfile) < 0,
	"Error saving the template file!");
    notify(player, "Saving complete!");
}

void mechrep_Rsetarmor(dbref player, void *data, char *buffer)
{
    char *args[4];
    int argc;
    int index;
    int temp;

    MECHREP_COMMON(1);
    argc = mech_parseattributes(buffer, args, 4);
    DOCHECK(!argc, "Invalid number of arguments!");
    index =
	ArmorSectionFromString(MechType(mech), MechMove(mech), args[0]);
    if (index == -1) {
	notify(player, "Not a legal area. Must be HEAD, CTORSO");
	notify(player, "LTORSO, RTORSO, RLEG, LLEG, RARM, LARM");
	notify(player, "TURRET, ROTOR, RSIDE, LSIDE, FRONT, AFT");
	return;
    }
    argc--;
    if (argc) {
	temp = atoi(args[1]);
	if (temp < 0)
	    notify(player, "Invalid armor value!");
	else {
	    notify(player, "Front armor set!");
	    SetSectArmor(mech, index, temp);
	    SetSectOArmor(mech, index, temp);
	}
	argc--;
    }
    if (argc) {
	temp = atoi(args[2]);
	if (temp < 0)
	    notify(player, "Invalid Internal armor value!");
	else {
	    notify(player, "Internal armor set!");
	    SetSectInt(mech, index, temp);
	    SetSectOInt(mech, index, temp);
	}
	argc--;
    }
    if (argc) {
	temp = atoi(args[3]);
	if (index == CTORSO || index == RTORSO || index == LTORSO) {
	    if (temp < 0)
		notify(player, "Invalid Rear armor value!");
	    else {
		notify(player, "Rear armor set!");
		SetSectRArmor(mech, index, temp);
		SetSectORArmor(mech, index, temp);
	    }
	} else
	    notify(player, "Only the torso can have rear armor.");
    }
}

/* 
 * Handles the adding of weapons via the 'addweap' command in the form of:
 * addweap <weap> <loc> <crits> [<flags>]
 * Current Flags: O = OS, T = TC, R = Rear
 */
void mechrep_Raddweap(dbref player, void *data, char *buffer)
{
    char *args[20];	/* The argument array */
    int argc;		/* Count of arguments */
    int index;		/* Used to determine section validity */
    int weapindex;	/* Weapon index number */
    int weapnumcrits;	/* Number of crits the desired weapon occupies. */
    int weaptype;	/* The weapon type */
    int loop, temp;	/* Loop Counters */
    int isrear = 0;	/* Rear mounted? */
    int istc = 0;	/* Is the weap TC'd? */
    int isoneshot = 0;  /* If 1, weapon is a One-Shot (OS) Weap */
    int isrocket = 0;	/* Is this a rocket launcher? */
    int argstoiter;	/* Holder for figuring out how many args to scan */
    char flagholder;	/* Holder for flag comparisons */

    MECHREP_COMMON(1);
    
    argc = mech_parseattributes(buffer, args, 20);
    DOCHECK(argc < 3, "Invalid number of arguments!")
	    
    index = ArmorSectionFromString(MechType(mech), MechMove(mech), args[1]);
    if (index == -1) {
	notify_printf(player, "Not a legal area. Must be HEAD, CTORSO");
	notify_printf(player, "LTORSO, RTORSO, RLEG, LLEG, RARM, LARM");
	notify_printf(player, "TURRET, ROTOR, RSIDE, LSIDE, FRONT, AFT");
	return;
    }
    
    weapindex = WeaponIndexFromString(args[0]);
    
    if (weapindex == -1) {
	notify_printf(player, "That is not a valid weapon!");
	DumpWeapons(player);
	return;
    }

    /* 
     * There are always 3 arguments that preceed flags. 
     * addweap <weap> <loc> <crit>, 0, 1, and 2 respectively in args[][]. 
     * By subtracting 3, we figure out how many of our arguments are actually 
     * flags.
     */
    argstoiter = argc - 3;
    
    /*
     * Now we take those additional flags and look for matches. argc is 
     * decremented to keep track of how many of our arguments are crit
     * locations.
     */
    for (loop = 0; loop < argstoiter; loop++) {
	flagholder = toupper(args[3 + loop][0]);

	    if (flagholder == 'T') {
		/* Targeting Computer */
	        istc = 1;
	    } else if (flagholder == 'R') {
		/* Rear Mounted */
		isrear = 1;
	    } else if (flagholder == 'O') {
		/* One-Shot */
		isoneshot = 1;
	    }

	    /* 
	     * If it's a letter, it's not a crit location. If a
	     * player throws numbers in with the crit flags, then
	     * they'll see error messages about crit counts. Need
	     * to find a better way to fool-proof this.
	     */
	    if (isalpha(flagholder))
		    argc--;
	    
    } /* end for */
   
    /* Chop off the first the first two redundant args. */
    argc -= 2;

    weapnumcrits = GetWeaponCrits(mech, weapindex);
    
    /* Check to see if player gives enough crits and start adding if so. */
    if (argc < weapnumcrits) {
	notify_printf(player,
	    "Not enough critical slots specified! (Given: %i, Needed: %i)", 
	    argc, weapnumcrits);
    } else if (argc > weapnumcrits) {
	notify_printf(player,
	    "Too many critical slots specified! (Given: %i, Needed: %i)", 
	    argc, weapnumcrits);
    } else {
	for (loop = 0; loop < GetWeaponCrits(mech, weapindex); loop++) {
	    temp = atoi(args[2 + loop]);
	    temp--;		/* From 1 based to 0 based */
	    DOCHECK(temp < 0 ||
		temp > NUM_CRITICALS, "Bad critical location!");
	    MechSections(mech)[index].criticals[temp].type =
		(I2Weapon(weapindex));
	    MechSections(mech)[index].criticals[temp].firemode = 0;
	    MechSections(mech)[index].criticals[temp].ammomode = 0;

	    /* If this is a Rocket Launcher, use isrocket to set the OS flag */
	    if (MechWeapons[weapindex].special & ROCKET)
		isrocket = 1;

	    if (isrear)
		MechSections(mech)[index].criticals[temp].firemode |=
		    REAR_MOUNT;

	    if (istc)
		MechSections(mech)[index].criticals[temp].firemode |=
		    ON_TC;
	    
	    /* Rockets are OS too */
	    if (isoneshot || isrocket)
		MechSections(mech)[index].criticals[temp].firemode |=
		    OS_MODE;
	}
	if (IsAMS(weapindex)) {
	    if (MechWeapons[weapindex].special & CLAT)
		MechSpecials(mech) |= CL_ANTI_MISSILE_TECH;
	    else
		MechSpecials(mech) |= IS_ANTI_MISSILE_TECH;
	}
	notify_printf(player, "Weapon added.");
    }
} /* end mechrep_Raddweap() */

void mechrep_Rreload(dbref player, void *data, char *buffer)
{
    char *args[4];
    int argc;
    int index;
    int weapindex;
    int subsect;

    MECHREP_COMMON(1);
    argc = mech_parseattributes(buffer, args, 4);
    DOCHECK(argc <= 2, "Invalid number of arguments!");
    weapindex = WeaponIndexFromString(args[0]);
    if (weapindex == -1) {
	notify(player, "That is not a valid weapon!");
	DumpWeapons(player);
	return;
    }
    index =
	ArmorSectionFromString(MechType(mech), MechMove(mech), args[1]);
    if (index == -1) {
	notify(player, "Not a legal area. Must be HEAD, CTORSO");
	notify(player, "LTORSO, RTORSO, RLEG, LLEG, RARM, LARM");
	notify(player, "TURRET, ROTOR, RSIDE, LSIDE, FRONT, AFT");
	return;
    }
    subsect = atoi(args[2]);
    subsect--;			/* from 1 based to 0 based */
    DOCHECK(subsect < 0 ||
	subsect >= CritsInLoc(mech, index), "Critslot out of range!");
    if (MechWeapons[weapindex].ammoperton == 0)
	notify(player, "That weapon doesn't require ammo!");
    else {
	MechSections(mech)[index].criticals[subsect].type =
	    I2Ammo(weapindex);
	MechSections(mech)[index].criticals[subsect].firemode = 0;
	MechSections(mech)[index].criticals[subsect].ammomode = 0;

	if (argc > 3)
	    switch (toupper(args[3][0])) {
	    case 'W':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    SWARM_MODE;
		break;
	    case '1':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    SWARM1_MODE;
		break;
	    case 'I':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    INFERNO_MODE;
		break;
	    case 'L':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    LBX_MODE;
		break;
	    case 'A':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    ARTEMIS_MODE;
		break;
	    case 'N':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    NARC_MODE;
		break;
	    case 'C':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    CLUSTER_MODE;
		break;
	    case 'M':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    MINE_MODE;
		break;
	    case 'S':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    SMOKE_MODE;
		break;
	    case 'X':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    INARC_EXPLO_MODE;
		break;
	    case 'Y':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    INARC_HAYWIRE_MODE;
		break;
	    case 'E':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    INARC_ECM_MODE;
		break;
	    case 'R':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    AC_AP_MODE;
		break;
	    case 'F':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    AC_FLECHETTE_MODE;
		break;
	    case 'D':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    AC_INCENDIARY_MODE;
		break;
	    case 'P':
		MechSections(mech)[index].criticals[subsect].ammomode |=
		    AC_PRECISION_MODE;
		break;
            case 'T':
                MechSections(mech)[index].criticals[subsect].ammomode |=
                    STINGER_MODE;
                break;
	    }

	MechSections(mech)[index].criticals[subsect].data =
	    FullAmmo(mech, index, subsect);
	notify(player, "Weapon loaded!");
    }
}

void mechrep_Rrepair(dbref player, void *data, char *buffer)
{
    char *args[4];
    int argc;
    int index;
    int temp;

    MECHREP_COMMON(1);
    argc = mech_parseattributes(buffer, args, 4);
    DOCHECK(argc <= 2, "Invalid number of arguments!");
    index =
	ArmorSectionFromString(MechType(mech), MechMove(mech), args[0]);
    if (index == -1) {
	notify(player, "Not a legal area. Must be HEAD, CTORSO");
	notify(player, "LTORSO, RTORSO, RLEG, LLEG, RARM, LARM");
	notify(player, "TURRET, ROTOR, RSIDE, LSIDE, FRONT, AFT");
	return;
    }
    temp = atoi(args[2]);
    DOCHECK(temp < 0, "Illegal value for armor!");
    switch (args[1][0]) {
    case 'A':
    case 'a':
	/* armor */
	SetSectArmor(mech, index, temp);
	notify(player, "Armor repaired!");
	break;
    case 'I':
    case 'i':
	/* internal */
	SetSectInt(mech, index, temp);
	notify(player, "Internal structure repaired!");
	break;
    case 'C':
    case 'c':
	/* criticals */
	temp--;
	if (temp >= 0 && temp < NUM_CRITICALS) {
	    MechSections(mech)[index].criticals[temp].data = 0;
	    notify(player, "Critical location repaired!");
	} else {
	    notify(player, "Critical Location out of range!");
	}
	break;
    case 'R':
    case 'r':
	/* rear */
	if (index == CTORSO || index == LTORSO || index == RTORSO) {
	    SetSectRArmor(mech, index, temp);
	    notify(player, "Rear armor repaired!");
	} else {
	    notify(player,
		"Only the center, rear and left torso have rear armor!");
	}
	break;
    default:
	notify(player,
	    "Illegal Type-> must be ARMOR, INTERNAL, CRIT, REAR");
	return;
    }
}

/*
   ADDSP <ITEM> <LOCATION> <SUBSECT> [<DATA>]
 */
void mechrep_Raddspecial(dbref player, void *data, char *buffer)
{
    char *args[4];
    int argc;
    int index;
    int itemcode;
    int subsect;
    int newdata;
    int max;

    MECHREP_COMMON(1);
    argc = mech_parseattributes(buffer, args, 4);
    DOCHECK(argc <= 2, "Invalid number of arguments!");
    itemcode = FindSpecialItemCodeFromString(args[0]);
    if (itemcode == -1)
	if (strcasecmp(args[0], "empty")) {
	    notify(player, "That is not a valid special object!");
	    DumpMechSpecialObjects(player);
	    return;
	}
    index =
	ArmorSectionFromString(MechType(mech), MechMove(mech), args[1]);
    if (index == -1) {
	notify(player, "Not a legal area. Must be HEAD, CTORSO");
	notify(player, "LTORSO, RTORSO, RLEG, LLEG, RARM, LARM");
	notify(player, "TURRET, ROTOR, RSIDE, LSIDE, FRONT, AFT");
	return;
    }
    subsect = atoi(args[2]);
    subsect--;
    max = CritsInLoc(mech, index);
    DOCHECK(subsect < 0 || subsect >= max, "Critslot out of range!");
    if (argc == 4)
	newdata = atoi(args[3]);
    else
	newdata = 0;
    MechSections(mech)[index].criticals[subsect].type =
	itemcode < 0 ? 0 : I2Special(itemcode);
    MechSections(mech)[index].criticals[subsect].data = newdata;
    switch (itemcode) {
    case CASE:
	MechSections(mech)[(MechType(mech) ==
		CLASS_VEH_GROUND) ? BSIDE : index].config |= CASE_TECH;
	notify(player, "CASE Technology added to section.");
	break;
    case TRIPLE_STRENGTH_MYOMER:
	MechSpecials(mech) |= TRIPLE_MYOMER_TECH;
	notify(player,
	    "Triple Strength Myomer Technology added to 'Mech.");
	break;
    case MASC:
	MechSpecials(mech) |= MASC_TECH;
	notify(player,
	    "Myomer Accelerator Signal Circuitry added to 'Mech.");
	break;
    case C3_MASTER:
	MechSpecials(mech) |= C3_MASTER_TECH;
	notify(player, "C3 Command Unit added to 'Mech.");
	break;
    case C3_SLAVE:
	MechSpecials(mech) |= C3_SLAVE_TECH;
	notify(player, "C3 Slave Unit added to 'Mech.");
	break;
    case ARTEMIS_IV:
	MechSections(mech)[index].criticals[subsect].data--;
	MechSpecials(mech) |= ARTEMIS_IV_TECH;
	notify(player, "Artemis IV Fire-Control System added to 'Mech.");
	notify(player,
	    tprintf
	    ("System will control the weapon which starts at slot %d.",
		newdata));
	break;
    case ECM:
	MechSpecials(mech) |= ECM_TECH;
	notify(player, "Guardian ECM Suite added to 'Mech.");
	break;
    case ANGELECM:
	MechSpecials2(mech) |= ANGEL_ECM_TECH;
	notify(player, "Angel ECM Suite added to 'Mech.");
	break;
    case BEAGLE_PROBE:
	MechSpecials(mech) |= BEAGLE_PROBE_TECH;
	notify(player, "Beagle Active Probe added to 'Mech.");
	break;
    case TAG:
	MechSpecials2(mech) |= TAG_TECH;
	notify(player, "TAG added to 'Mech.");
	break;
    case C3I:
	MechSpecials2(mech) |= C3I_TECH;
	notify(player, "Improved C3 added to 'Mech.");
	break;
    case BLOODHOUND_PROBE:
	MechSpecials2(mech) |= BLOODHOUND_PROBE_TECH;
	notify(player, "Bloodhound Active Probe added to 'Mech.");
	break;
    }
    notify(player, "Critical slot filled.");
}

extern char *specials[];
extern char *specials2[];
extern char *infantry_specials[];

char *techstatus_func(MECH * mech)
{
    return (MechSpecials(mech) ||
	MechSpecials2(mech)) ? BuildBitString2(specials, specials2,
	MechSpecials(mech), MechSpecials2(mech)) : "";
}

void mechrep_Rshowtech(dbref player, void *data, char *buffer)
{
    int i;
    char *techstring;
    char location[20];

    MECHREP_COMMON(1);
    notify(player, "--------Advanced Technology--------");
    if (MechSpecials(mech) & TRIPLE_MYOMER_TECH)
	notify(player, "Triple Strength Myomer");
    if (MechSpecials(mech) & MASC_TECH)
	notify(player, "Myomer Accelerator Signal Circuitry");
    for (i = 0; i < NUM_SECTIONS; i++)
	if (MechSections(mech)[i].config & CASE_TECH) {
	    ArmorStringFromIndex(i, location, MechType(mech),
		MechMove(mech));
	    notify(player,
		tprintf("Cellular Ammunition Storage Equipment in %s",
		    location));
	}
    if (MechSpecials(mech) & CLAN_TECH) {
	notify(player, "Mech is set to Clan Tech.  This means:");
	notify(player, "    Mech automatically has Double Heat Sink Tech");
	notify(player, "    Mech automatically has CASE in all sections");
    }
    if (MechSpecials(mech) & DOUBLE_HEAT_TECH)
	notify(player, "Mech uses Double Heat Sinks");
    if (MechSpecials(mech) & CL_ANTI_MISSILE_TECH)
	notify(player, "Clan style Anti-Missile System");
    if (MechSpecials(mech) & IS_ANTI_MISSILE_TECH)
	notify(player, "Inner Sphere style Anti-Missile System");
    if (MechSpecials(mech) & FLIPABLE_ARMS)
	notify(player, "The arms may be flipped into the rear firing arc");
    if (MechSpecials(mech) & C3_MASTER_TECH)
	notify(player, "C3 Command Computer");
    if (MechSpecials(mech) & C3_SLAVE_TECH)
	notify(player, "C3 Slave Computer");
    if (MechSpecials(mech) & ARTEMIS_IV_TECH)
	notify(player, "Artemis IV Fire-Control System");
    if (MechSpecials(mech) & ECM_TECH)
	notify(player, "Guardian ECM Suite");
    if (MechSpecials2(mech) & ANGEL_ECM_TECH)
	notify(player, "Angel ECM Suite");
    if (MechSpecials(mech) & BEAGLE_PROBE_TECH)
	notify(player, "Beagle Active Probe");
    if (MechSpecials2(mech) & TAG_TECH)
	notify(player, "Target Aquisition Gear");
    if (MechSpecials2(mech) & C3I_TECH)
	notify(player, "Improved C3");
    if (MechSpecials2(mech) & BLOODHOUND_PROBE_TECH)
	notify(player, "Bloodhound Active Probe");
    if (MechSpecials(mech) & ICE_TECH)
	notify(player, "It has ICE engine");

    /* Infantry related stuff */
    if (MechInfantrySpecials(mech) & INF_SWARM_TECH)
	notify(player, "Can swarm enemy units");
    if (MechInfantrySpecials(mech) & INF_MOUNT_TECH)
	notify(player, "Can mount friendly units");
    if (MechInfantrySpecials(mech) & INF_ANTILEG_TECH)
	notify(player, "Can do anti-leg attacks");
    if (MechInfantrySpecials(mech) & CS_PURIFIER_STEALTH_TECH)
	notify(player, "Has CS Purifier Stealth");
    if (MechInfantrySpecials(mech) & DC_KAGE_STEALTH_TECH)
	notify(player, "Has DC Kage Stealth");
    if (MechInfantrySpecials(mech) & FWL_ACHILEUS_STEALTH_TECH)
	notify(player, "Has FWL Achileus Stealth");
    if (MechInfantrySpecials(mech) & FC_INFILTRATOR_STEALTH_TECH)
	notify(player, "Has FC Infiltrator Stealth");
    if (MechInfantrySpecials(mech) & FC_INFILTRATORII_STEALTH_TECH)
	notify(player, "Has FC InfiltratorII Stealth");
    if (MechInfantrySpecials(mech) & MUST_JETTISON_TECH)
	notify(player,
	    "Must jettison backpack before jumping/using specials");
    if (MechInfantrySpecials(mech) & CAN_JETTISON_TECH)
	notify(player, "Can jettison backpack");

    notify(player, "Brief version (May have something previous hadn't):");
    techstring = mechrep_gettechstring(mech);
    if (techstring && techstring[0])
        notify(player, techstring);
    else
    	notify(player, "-");
}

char * mechrep_gettechstring(MECH *mech)
{
    return BuildBitString3(specials, specials2, infantry_specials,
			   MechSpecials(mech), MechSpecials2(mech),
			   MechInfantrySpecials(mech));
}

void mechrep_Rdeltech(dbref player, void *data, char *buffer)
{
    int i, j;
    int Type;
    int nv, nv2;

    MECHREP_COMMON(1);
    /* Compare what the user gave to our specials lists */
    nv = BuildBitVector(specials, buffer);
    nv2 = BuildBitVector(specials2, buffer);

    /* Make sure what they gave was valid */
    if (((nv < 0) && (nv2 < 0)) && (strcasecmp(buffer, "all") != 0) && 
            (strcasecmp(buffer, "Case") != 0)) {
	    notify(player, "Invalid tech: Available techs:");
        notify(player, "\tAll");
        notify(player, "\tCase");

	    for (nv = 0; specials[nv]; nv++)
	        notify(player, tprintf("\t%s", specials[nv]));

	    for (nv = 0; specials2[nv]; nv++)
	        notify(player, tprintf("\t%s", specials2[nv]));

	    return;
    }

    /* Check to see if user specified anything */
    if (((!nv) && (!nv2)) && (strcasecmp(buffer, "all") != 0) && 
            (strcasecmp(buffer, "Case") != 0)) {
	    notify(player, "Nothing specified");
	    return;
    }

    /* Check to see if user specified 'ALL' */
    if (strcasecmp(buffer, "all") == 0) {

        for (i = 0; i < NUM_SECTIONS; i++) {

	        if ((MechSections(mech)[i].config & CASE_TECH)
	            || (MechSpecials(mech) & TRIPLE_MYOMER_TECH)
	            || (MechSpecials(mech) & MASC_TECH)) {
	            
                for (j = 0; j < NUM_CRITICALS; j++) {
		            Type = MechSections(mech)[i].criticals[j].type;

		            if (Type == I2Special((CASE))
		                || Type == I2Special((TRIPLE_STRENGTH_MYOMER))
		                || Type == I2Special((MASC))) {
		                MechSections(mech)[i].criticals[j].type = EMPTY;
                    }
                }
	            MechSections(mech)[i].config &= ~CASE_TECH;

            }
        }

        MechSpecials(mech) = 0;
        MechSpecials2(mech) = 0;
        notify(player, "All Advanced Technology Removed");
        return;
    }

    if (strcasecmp(buffer, "Case") == 0) {
        for (i = 0; i < NUM_SECTIONS; i++) {
	        if (MechSections(mech)[i].config & CASE_TECH) { 
                for (j = 0; j < NUM_CRITICALS; j++) {
	                Type = MechSections(mech)[i].criticals[j].type;

		            if (Type == I2Special((CASE))) {
		                MechSections(mech)[i].criticals[j].type = EMPTY;
                    }
                }
	            MechSections(mech)[i].config &= ~CASE_TECH;
            }
        }
        notify(player, "Case Technology Removed");
        return;
    }

    if (nv > 0) {

        if (strcasecmp(buffer, "TripleMyomerTech") == 0) {
            if (MechSpecials(mech) & TRIPLE_MYOMER_TECH) {
                for (i = 0; i < NUM_SECTIONS; i++) {
                    for (j = 0; j < NUM_CRITICALS; j++) {
		                Type = MechSections(mech)[i].criticals[j].type;

		                if (Type == I2Special((TRIPLE_STRENGTH_MYOMER))) {
		                    MechSections(mech)[i].criticals[j].type = EMPTY;
                        }
                    }
                }
            }
        } else if (strcasecmp(buffer, "Masc") == 0) {
            if (MechSpecials(mech) & MASC_TECH) {
                for (i = 0; i < NUM_SECTIONS; i++) {
                    for (j = 0; j < NUM_CRITICALS; j++) {
		                Type = MechSections(mech)[i].criticals[j].type;

		                if (Type == I2Special((MASC))) {
		                    MechSections(mech)[i].criticals[j].type = EMPTY;
                        }
                    }
                }
            }
        }

	    MechSpecials(mech) &= ~nv;
    	notify(player, tprintf("%s Technology Removed", buffer));
        
    } else {

	    MechSpecials2(mech) &= ~nv2;
	    notify(player, tprintf("%s Technology Removed", buffer));

    }
    return;
}

void mechrep_Raddtech(dbref player, void *data, char *buffer)
{
    int nv, nv2;

    MECHREP_COMMON(1);
    nv = BuildBitVector(specials, buffer);
    nv2 = BuildBitVector(specials2, buffer);

    if ((nv < 0) && (nv2 < 0)) {
	notify(player, "Invalid tech: Available techs:");

	for (nv = 0; specials[nv]; nv++)
	    notify(player, tprintf("\t%s", specials[nv]));

	for (nv = 0; specials2[nv]; nv++)
	    notify(player, tprintf("\t%s", specials2[nv]));

	return;
    }

    if ((!nv) && (!nv2)) {
	notify(player, "Nothing set!");
	return;
    }

    if (nv > 0) {
	MechSpecials(mech) |= nv;
	notify(player, tprintf("Set: %s", BuildBitString(specials, nv)));
    } else {
	MechSpecials2(mech) |= nv2;
	notify(player, tprintf("Set: %s", BuildBitString(specials2, nv2)));
    }

}

void mechrep_Rdelinftech(dbref player, void *data, char *buffer)
{
    MECH *mech = (MECH *) data;

    MechInfantrySpecials(mech) = 0;
    notify(player, "Advanced Infantry Technology Deleted");
}

void mechrep_Raddinftech(dbref player, void *data, char *buffer)
{
    int nv;

    MECHREP_COMMON(1);
    nv = BuildBitVector(infantry_specials, buffer);

    if (nv < 0) {
	notify(player, "Invalid infantry tech: Available techs:");

	for (nv = 0; infantry_specials[nv]; nv++)
	    notify(player, tprintf("\t%s", infantry_specials[nv]));
	return;
    }

    if (!nv) {
	notify(player, "Nothing set!");
	return;
    }

    if (nv > 0) {
	MechInfantrySpecials(mech) |= nv;
	notify(player, tprintf("Set: %s", BuildBitString(infantry_specials,
		    nv)));
    }

}

void mechrep_setcargospace(dbref player, void *data, char *buffer)
{
    char *args[2];
    int argc;
    int cargo;
    int max;

    MECHREP_COMMON(1);
    argc = mech_parseattributes(buffer, args, 2);
    DOCHECK(argc != 2, "Invalid number of arguements!");

    cargo = (atoi(args[0]) * 50);
    DOCHECK(cargo < 0 || cargo > 100000, "Doesn't that seem excessive?");
    CargoSpace(mech) = cargo;

    max = (atoi(args[1]));
    max = (BOUNDED(1,max,100));
    CarMaxTon(mech) = (char) max;

    notify(player, tprintf("%3.2f cargospace and %d tons of maxton space set.", (float) ((float) cargo / 100), (int) max));

}

MECH *load_refmech(char *reference)
{
    static MECH cachemech;
    static char cacheref[1024];

    if (!strcmp(cacheref, reference))
	return &cachemech;
    if (mech_loadnew(GOD, &cachemech, reference) < 1) {
	cacheref[0] = '\0';
	return NULL;
    }
    strncpy(cacheref, reference, 1023);
    cacheref[1023] = '\0';
    return &cachemech;
}