wileymud-1.187b/
wileymud-1.187b/attic/
wileymud-1.187b/attic/bin/
wileymud-1.187b/attic/lib/
wileymud-1.187b/attic/lib/adm/
wileymud-1.187b/attic/lib/man/
wileymud-1.187b/attic/lib/new-wld/
wileymud-1.187b/attic/lib/new-wld/default/
wileymud-1.187b/attic/lib/old/
wileymud-1.187b/attic/lib/wld/
wileymud-1.187b/attic/public_html/
wileymud-1.187b/attic/public_html/gfx/
wileymud-1.187b/attic/src/bin/
wileymud-1.187b/attic/src/etc/
wileymud-1.187b/attic/src/libauth-4.0-p5/
wileymud-1.187b/attic/src/sedna/
wileymud-1.187b/backups/
wileymud-1.187b/bin/
wileymud-1.187b/docs/
wileymud-1.187b/etc/
wileymud-1.187b/lib/
wileymud-1.187b/lib/adm/
wileymud-1.187b/lib/boards/
wileymud-1.187b/lib/log/
wileymud-1.187b/lib/man/
wileymud-1.187b/lib/ply/
wileymud-1.187b/lib/ply/a/
wileymud-1.187b/lib/ply/b/
wileymud-1.187b/lib/ply/c/
wileymud-1.187b/lib/ply/d/
wileymud-1.187b/lib/ply/g/
wileymud-1.187b/lib/ply/k/
wileymud-1.187b/lib/ply/m/
wileymud-1.187b/lib/ply/s/
wileymud-1.187b/lib/ply/t/
wileymud-1.187b/public_html/gfx/
wileymud-1.187b/src/bin/
wileymud-1.187b/src/convert/attic/
wileymud-1.187b/src/convert/obj/
wileymud-1.187b/src/convert/perl/
wileymud-1.187b/src/convert/perl/MudConvert/
wileymud-1.187b/src/convert/perl/MudConvert/DUMP/
wileymud-1.187b/src/convert/perl/MudConvert/Report/
wileymud-1.187b/src/convert/perl/MudConvert/WileyMUD/
wileymud-1.187b/src/convert/perl/output/
wileymud-1.187b/src/convert/perl/output/DUMP/
wileymud-1.187b/src/convert/perl/output/Report/
wileymud-1.187b/src/convert/perl/output/WileyMUD/
wileymud-1.187b/src/etc/
wileymud-1.187b/src/etc/init.d/
wileymud-1.187b/src/etc/rc.d/
wileymud-1.187b/src/etc/rc.d/init.d/
wileymud-1.187b/src/lib/
wileymud-1.187b/src/lib/adm/
wileymud-1.187b/src/lib/boards/
wileymud-1.187b/src/lib/log/
wileymud-1.187b/src/lib/man/
wileymud-1.187b/src/lib/ply/
wileymud-1.187b/src/lib/ply/a/
wileymud-1.187b/src/lib/ply/b/
wileymud-1.187b/src/lib/ply/c/
wileymud-1.187b/src/lib/ply/d/
wileymud-1.187b/src/lib/ply/e/
wileymud-1.187b/src/lib/ply/f/
wileymud-1.187b/src/lib/ply/g/
wileymud-1.187b/src/lib/ply/h/
wileymud-1.187b/src/lib/ply/i/
wileymud-1.187b/src/lib/ply/j/
wileymud-1.187b/src/lib/ply/k/
wileymud-1.187b/src/lib/ply/l/
wileymud-1.187b/src/lib/ply/m/
wileymud-1.187b/src/lib/ply/n/
wileymud-1.187b/src/lib/ply/o/
wileymud-1.187b/src/lib/ply/p/
wileymud-1.187b/src/lib/ply/q/
wileymud-1.187b/src/lib/ply/r/
wileymud-1.187b/src/lib/ply/s/
wileymud-1.187b/src/lib/ply/t/
wileymud-1.187b/src/lib/ply/u/
wileymud-1.187b/src/lib/ply/v/
wileymud-1.187b/src/lib/ply/w/
wileymud-1.187b/src/lib/ply/x/
wileymud-1.187b/src/lib/ply/y/
wileymud-1.187b/src/lib/ply/z/
wileymud-1.187b/src/obj/
wileymud-1.187b/src/utils/
wileymud-1.187b/src/utils/mobmaker/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>

#include "include/bug.h"
#include "include/structs.h"
#include "include/main.h"
#include "include/utils.h"
#include "include/make_index.h"

#define _PARSE_WILEY_C
#include "include/parse_wiley.h"

const int                               SectorCosts[] = { 0, 1, 2, 2, 3, 4, 6, 8, 10, 2, 20 };
const int                               RevDir[] = { 2, 3, 0, 1, 5, 4 };

/*
 * This routine loads a zone file (in WileyMUD DikuMUD format) and returns a
 * structure containing all the information it contained.
 */
zones                                  *load_zones(char *infile)
{
    FILE                                   *ifp;
    vnum_index                             *ZoneIndex;
    zones                                  *Zones;
    char                                   *tmp;
    register int                            i,
                                            j;
    long                                    Line,
                                            Pos;

    if (!infile || !*infile)
	return NULL;
    if (!(ZoneIndex = make_index(infile, NULL)))
	return NULL;
    Zones = (zones *)get_mem(1, sizeof(zones));
    bzero(Zones, sizeof(zones));
    Zones->Count = ZoneIndex->Count;
    Zones->Zone = (zone *)get_mem(Zones->Count, sizeof(zone));
    bzero(Zones->Zone, Zones->Count * sizeof(zone));
    ifp = open_file(infile, "r");

    if (!Quiet) {
	fprintf(stderr, "Parsing Zone file...");
	fflush(stderr);
    }

    for (i = 0; i < Zones->Count; i++) {
	Line = ZoneIndex->VNum[i].Line;
	Pos = ZoneIndex->VNum[i].Pos;
	Zones->Zone[i].Number = ZoneIndex->VNum[i].Number;
	if (fseek(ifp, Pos, 0) < 0)
	    log_fatal("Cannot load Zone #%d from %s!", Zones->Zone[i].Number, infile);
	if (!(tmp = get_line(ifp, &Line, &Pos, 1)))
	    log_fatal("Cannot get vnum for Zone #%d from %s!", Zones->Zone[i].Number, infile);
	if (!(tmp = get_tilde_string(ifp, &Line, &Pos)))
	    log_fatal("Missing zone name at line %d of %s.", Line, infile);
	Zones->Zone[i].Name = my_strdup(tmp);
	if (!(tmp = get_line(ifp, &Line, &Pos, 1)))
	    log_fatal("Missing flag line in %s at %d.", infile, Line);
	if (sscanf(tmp, " %d %d %d ", &(Zones->Zone[i].Top), &(Zones->Zone[i].Time),
		   &(Zones->Zone[i].Mode)) != 3)
	    log_fatal("Corrupt flag line in %s at %d.", infile, Line);

	Zones->Zone[i].Cmds = (zone_cmds *)get_mem(1, sizeof(zone_cmds));
	bzero(Zones->Zone[i].Cmds, sizeof(zone_cmds));
	for (j = Zones->Zone[i].Count = 0; (tmp = get_line(ifp, &Line, &Pos, 1));) {
	    if (*tmp == ZONE_CMD_END) {
		/*
		 * if(Zones->Zone[i].Count > 0) Zones->Zone[i].Count--; 
		 */
		break;
	    } else if ((*tmp == ZONE_CMD_MOBILE) || (*tmp == ZONE_CMD_OBJECT) ||
		       (*tmp == ZONE_CMD_EQUIP) || (*tmp == ZONE_CMD_PUT) ||
		       (*tmp == ZONE_CMD_DOOR)) {
		if (sscanf(tmp, "%c %d %d %d %d ",
			   &(Zones->Zone[i].Cmds[j].Command),
			   &(Zones->Zone[i].Cmds[j].IfFlag),
			   &(Zones->Zone[i].Cmds[j].Arg[0]),
			   &(Zones->Zone[i].Cmds[j].Arg[1]),
			   &(Zones->Zone[i].Cmds[j].Arg[2])) != 5) {
		    if (Debug)
			log_error("Bad args to Zone command, %s at %d.", infile, Line);
		    continue;
		}
		if (Verbose)
		    fprintf(stderr, "Zone [#%d] Command %d:  %c %d %d %d %d\n",
			    Zones->Zone[i].Number,
			    j, Zones->Zone[i].Cmds[j].Command,
			    Zones->Zone[i].Cmds[j].IfFlag,
			    Zones->Zone[i].Cmds[j].Arg[0],
			    Zones->Zone[i].Cmds[j].Arg[1], Zones->Zone[i].Cmds[j].Arg[2]);
		else if (!Quiet)
		    spin(stderr);
	    } else if ((*tmp == ZONE_CMD_GIVE) || (*tmp == ZONE_CMD_REMOVE) ||
		       (*tmp == ZONE_CMD_LEAD) || (*tmp == ZONE_CMD_HATE)) {
		if (sscanf(tmp, "%c %d %d %d ",
			   &(Zones->Zone[i].Cmds[j].Command),
			   &(Zones->Zone[i].Cmds[j].IfFlag),
			   &(Zones->Zone[i].Cmds[j].Arg[0]),
			   &(Zones->Zone[i].Cmds[j].Arg[1])) != 4) {
		    if (Debug)
			log_error("Bad args to Zone command, %s at %d.", infile, Line);
		    continue;
		}
		if (Verbose)
		    fprintf(stderr, "Zone [#%d] Command %d:  %c %d %d %d\n",
			    Zones->Zone[i].Number,
			    j, Zones->Zone[i].Cmds[j].Command,
			    Zones->Zone[i].Cmds[j].IfFlag,
			    Zones->Zone[i].Cmds[j].Arg[0], Zones->Zone[i].Cmds[j].Arg[1]);
		else if (!Quiet)
		    spin(stderr);
	    } else {
		if (Debug)
		    log_error("Unrecognized Zone command ignored, %s at %d.", infile, Line);
		continue;
	    }
	    j = ++Zones->Zone[i].Count;
	    Zones->Zone[i].Cmds =
		(zone_cmds *)get_more_mem((char *)Zones->Zone[i].Cmds,
					  j + 1, sizeof(zone_cmds));
	    bzero(&(Zones->Zone[i].Cmds[j]), sizeof(zone_cmds));
	}
    }
    fclose(ifp);
    if (!Quiet)
	fprintf(stderr, "done.\n");
    return Zones;
}

char                                   *zone_reset_name(int Reset)
{
    switch (Reset) {
	case ZONE_RESET_NEVER:
	    return "Never";
	case ZONE_RESET_PC:
	    return "if No Players are present";
	case ZONE_RESET_ALWAYS:
	    return "Always";
	default:
	    return "unknown";
    }
}

int remap_zone_vnum(zones *Zones, int VNum)
{
    register int                            i;

    for (i = 0; i < Zones->Count; i++)
	if (Zones->Zone[i].Number == VNum)
	    return i;
    return -1;
}

char                                   *zone_name(zones *Zones, int VNum)
{
    int                                     i;

    if ((i = remap_zone_vnum(Zones, VNum)) != -1)
	return Zones->Zone[i].Name;
    else
	return "a non-existant zone";
}

/*
 * Here begins the Great Room Parser.... bowworshipgrovel
 */
char                                   *exit_name(int Direction)
{
    switch (Direction) {
	case EXIT_NORTH:
	    return ("North");
	case EXIT_EAST:
	    return ("East");
	case EXIT_SOUTH:
	    return ("South");
	case EXIT_WEST:
	    return ("West");
	case EXIT_UP:
	    return ("Up");
	case EXIT_DOWN:
	    return ("Down");
	default:
	    return ("unknown");
    }
}

char                                   *exit_name_lower(int Direction)
{
    switch (Direction) {
	case EXIT_NORTH:
	    return ("north");
	case EXIT_EAST:
	    return ("east");
	case EXIT_SOUTH:
	    return ("south");
	case EXIT_WEST:
	    return ("west");
	case EXIT_UP:
	    return ("up");
	case EXIT_DOWN:
	    return ("down");
	default:
	    return ("unknown");
    }
}

int remap_room_vnum(rooms *Rooms, int VNum)
{
    register int                            i;

    for (i = 0; i < Rooms->Count; i++)
	if (Rooms->Room[i].Number == VNum)
	    return i;
    return -1;
}

char                                   *room_name(rooms *Rooms, int VNum)
{
    int                                     i;

    if ((i = remap_room_vnum(Rooms, VNum)) != -1)
	return Rooms->Room[i].                  Name;

    else
	return "a non-existant room";
}

void fix_exit_vnums(rooms *Rooms)
{
    register int                            i,
                                            j;

    if (!Quiet) {
	fprintf(stderr, "Fixing exit vnums to physical mappings...");
	fflush(stderr);
    }
    for (i = 0; i < Rooms->Count; i++) {
	for (j = 0; j < Rooms->Room[i].ExitCount; j++) {
	    if (!Quiet)
		spin(stderr);
	    if (Rooms->Room[i].Exit[j].Error == EXIT_OK) {
		if (Rooms->Room[i].Exit[j].Room <0) {
		    Rooms->Room[i].                         Exit[j].Error =
			EXIT_DESCRIPTION_ONLY;
		    Rooms->Room[i].                         Exit[j].RoomIndex = EXIT_INVALID;

		    if (Debug)
			log_error("DESCRIPTION-ONLY exit found as %s exit of Room \"%s\"[#%d].",
				  exit_name(Rooms->Room[i].Exit[j].Direction),
				  room_name(Rooms, Rooms->Room[i].Number),
				  Rooms->Room[i].Number);
		} else
		    Rooms->Room[i].                         Exit[j].RoomIndex =
			remap_room_vnum(Rooms, Rooms->Room[i].Exit[j].Room);
	    }
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void check_duplicate_rooms(rooms *Rooms)
{
    register int                            i,
                                            tmp;

    if (!Quiet) {
	fprintf(stderr, "Checking for duplicate room vnums...");
	fflush(stderr);
    }
    for (i = 0; i < Rooms->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	tmp = Rooms->Room[i].                   Number;
	Rooms->Room[i].                         Number = -1;

	if (remap_room_vnum(Rooms, tmp) >= 0)
	    if (Debug)
		log_error("ROOM [#%d] is DUPLICATED!!!", tmp);
	Rooms->Room[i].                         Number = tmp;
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void verify_exits(rooms *Rooms)
{
    register int                            i,
                                            j,
                                            k,
                                            real,
                                            back;

    if (!Quiet) {
	fprintf(stderr, "Verifying exit consistancy...");
	fflush(stderr);
    }
    for (i = 0; i < Rooms->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	if (Rooms->Room[i].ExitCount < 1) {
	    if (Rooms->Room[i].Sector != SECT_TELEPORT) {
		if (Debug)
		    log_error("NO-EXITS in Room \"%s\"[#%d]!",
			      room_name(Rooms, Rooms->Room[i].Number), Rooms->Room[i].Number);
	    } else {
		if (Rooms->Room[i].TeleportTime < 0) {
		    if (Debug)
			log_error("TELEPORT TIME INVALID for Room \"%s\"[#%d]!",
				  room_name(Rooms, Rooms->Room[i].Number),
				  Rooms->Room[i].Number);
		} else {
		    if (remap_room_vnum(Rooms, Rooms->Room[i].TeleportTo) < 0) {
			if (Debug)
			    log_error("NO-EXITS in Room \"%s\"[#%d]!  INVALID TELEPORT TARGET.",
				      room_name(Rooms, Rooms->Room[i].Number),
				      Rooms->Room[i].Number);
		    } else {
			if (Debug)
			    log_error("TELEPORT-ONLY exit in Room \"%s\"[#%d].",
				      room_name(Rooms, Rooms->Room[i].Number),
				      Rooms->Room[i].Number);
		    }
		}
	    }
	} else
	    for (j = 0; j < Rooms->Room[i].ExitCount; j++) {
		if (Rooms->Room[i].Exit[j].Error /* Direction */  != EXIT_OK) {
		    if (Debug)
			log_error("Room \"%s\"[#%d] has an INVALID exit! REMOVING!",
				  room_name(Rooms, Rooms->Room[i].Number),
				  Rooms->Room[i].Number);
		} else {
		    if ((real = Rooms->Room[i].Exit[j].RoomIndex)<0) {
			Rooms->Room[i].                         Exit[j].Error = EXIT_NO_TARGET;

			if (Debug)
			    log_error
				("INVALID-TARGET Room #%d does not exist!  REMOVING %s exit from Room \"%s\"[#%d].",
				 Rooms->Room[i].Exit[j].Room,
				 exit_name(Rooms->Room[i].Exit[j].Direction), room_name(Rooms,
											Rooms->Room
											[i].Number),
				 Rooms->Room[i].Number);
			/*
			 * Rooms->Room[i].Exit[j].Direction= EXIT_INVALID; 
			 */
		    } else {
			if (Rooms->Room[real].ExitCount < 1) {
			    if (Debug)
				log_error("NO-EXITS in Target Room \"%s\"[#%d]!",
					  room_name(Rooms, Rooms->Room[real].Number),
					  Rooms->Room[real].Number);
			} else {
			    back = -1;
			    for (k = 0; k < Rooms->Room[real].ExitCount; k++) {
				if (Rooms->Room[real].Exit[k].Direction ==
				    RevDir[Rooms->Room[i].Exit[j].Direction])
				                                            back = k;
			    }
			    if (back < 0) {
				Rooms->Room[i].                         Exit[j].Error =
				    EXIT_ONE_WAY;
				if (Debug)
				    log_error
					("ONE-WAY %s exit in Room \"%s\"[#%d]!  No matching %s exit in Target Room \"%s\"[#%d].",
					 exit_name(Rooms->Room[i].Exit[j].Direction),
					 room_name(Rooms, Rooms->Room[i].Number),
					 Rooms->Room[i].Number,
					 exit_name(RevDir[Rooms->Room[i].Exit[j].Direction]),
					 room_name(Rooms, Rooms->Room[real].Number),
					 Rooms->Room[real].Number);
			    } else {
				if (Rooms->Room[real].Exit[back].Room !=Rooms->Room[i].Number) {
				    Rooms->Room[i].                         Exit[j].Error =
					EXIT_NON_EUCLIDEAN;
				    if (Debug)
					log_error
					    ("NON-EUCLIDEAN mapping:  Room \"%s\"[#%d] %s -> Room \"%s\"[#%d] != Room \"%s\"[#%d] %s -> Room \"%s\"[#%d]!",
					     room_name(Rooms, Rooms->Room[i].Number),
					     Rooms->Room[i].Number,
					     exit_name(Rooms->Room[i].Exit[j].Direction),
					     room_name(Rooms, Rooms->Room[i].Exit[j].Room),
					     Rooms->Room[i].Exit[j].Room, room_name(Rooms,
										    Rooms->Room
										    [real].Number),
					     Rooms->Room[real].Number,
					     exit_name(Rooms->Room[real].Exit[back].Direction),
					     room_name(Rooms,
						       Rooms->Room[real].Exit[back].Room),
					     Rooms->Room[real].Exit[back].Room);
				}
			    }
			}
		    }
		}
	    }
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void fix_zone_ids(zones *Zones, rooms *Rooms)
{
    register int                            i,
                                            j,
                                            CorrectZone;

    if (!Quiet) {
	fprintf(stderr, "Fixing incorrect Zone id tags...");
	fflush(stderr);
    }
    for (i = 0; i < Rooms->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	CorrectZone = -1;
	for (j = 0; j < Zones->Count; j++)
	    if (Rooms->Room[i].Number <= Zones->Zone[j].Top)
		if (Rooms->Room[i].Number >= ((j > 0) ? Zones->Zone[j - 1].Top + 1 : 0)) {
		    CorrectZone = Zones->Zone[j].Number;
		    break;
		}
	if (CorrectZone == -1) {
	    if (Verbose)
		log_error("Holy BatTurds!  I have NO IDEA what zone this room [#%d] "
			  "belongs to!\nPutting it in Zone %d...\n",
			  Rooms->Room[i].Number, Zones->Zone[0].Number);
	    Rooms->Room[i].                         Zone = Zones->Zone[0].Number;
	} else if (Rooms->Room[i].Zone != CorrectZone) {
	    if (Debug)
		log_error("Incorrect Zone ID of [#%d] for room \"%s\" [#%d],\n"
			  "Remapping to Zone [#%d].\n",
			  Rooms->Room[i].Zone, Rooms->Room[i].Name,
			  Rooms->Room[i].Number, CorrectZone);
	    Rooms->Room[i].                         Zone = CorrectZone;
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void check_room_zone_mismatch(zones *Zones, rooms *Rooms)
{
    register int                            i,
                                            CorrectZone;

    if (!Quiet) {
	fprintf(stderr, "Verifying proper Zone id tags...");
	fflush(stderr);
    }
    for (i = 0; i < Rooms->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	CorrectZone = Rooms->Room[i].           Number / 100;

	if (Rooms->Room[i].Zone != CorrectZone) {
	    log_error("Improper Zone ID of [#%d] for room \"%s\" [#%d],\n"
		      "Should belong to Zone [#%d].\n",
		      Rooms->Room[i].Zone, Rooms->Room[i].Name,
		      Rooms->Room[i].Number, CorrectZone);
	    /*
	     * Rooms->Room[i].Zone= CorrectZone; 
	     */
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

/*
 * This routine loads the world file (in WileyMUD DikuMUD format) and returns a
 * structure containing all the information it contained.
 */
rooms                                  *load_rooms(char *infile, zones *Zones)
{
    FILE                                   *ifp;
    vnum_index                             *RoomIndex;
    rooms                                  *Rooms;
    char                                   *tmp;	       /* , tmp2[MAX_LINE_LEN], *tmp3; */
    register int                            i,
                                            j,
                                            e;
    long                                    Line,
                                            Pos;

    if (!infile || !*infile)
	return NULL;
    if (!(RoomIndex = make_index(infile, NULL)))
	return NULL;
    Rooms = (rooms *)get_mem(1, sizeof(rooms));
    bzero(Rooms, sizeof(rooms));
    Rooms->Count = RoomIndex->Count;
    Rooms->Room = (room *)get_mem(Rooms->Count, sizeof(room));
    bzero(Rooms->Room, Rooms->Count * sizeof(room));

    ifp = open_file(infile, "r");

    if (Verbose)
	fprintf(stderr, "Parsing World file...\n");
    else if (!Quiet) {
	fprintf(stderr, "Parsing World file...");
	fflush(stderr);
    }

    for (i = 0; i < Rooms->Count; i++) {
	Line = RoomIndex->VNum[i].Line;
	Pos = RoomIndex->VNum[i].Pos;
	Rooms->Room[i].                         Number = RoomIndex->VNum[i].Number;

	if (fseek(ifp, Pos, 0) < 0)
	    log_fatal("Cannot load Room $%d from %s!", Rooms->Room[i].Number, infile);

	if (!(tmp = get_line(ifp, &Line, &Pos, 1)))
	    log_fatal("Cannot get vnum for Room #%d from %s!", Rooms->Room[i].Number, infile);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Rooms->Room[i].Name = my_strdup(tmp))))
	    log_fatal("Cannot get name for Room #%d, %s at %d.",
		      Rooms->Room[i].Number, infile, Line);

	if (Verbose)
	    fprintf(stderr, "  (%d) Parsing \"%s\"[#%d]...\n", i,
		    Rooms->Room[i].Name, Rooms->Room[i].Number);
	else if (!Quiet)
	    spin(stderr);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Rooms->Room[i].Description = my_strdup(tmp))))
	    log_fatal("Cannot get description for Room #%d, %s at %d.",
		      Rooms->Room[i].Number, infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d %d %d ", &(Rooms->Room[i].Zone),
		    &(Rooms->Room[i].Flags), &(Rooms->Room[i].Sector)) != 3)) {
	    if (Debug)
		log_error("Bug in MAIN flags for Room #%d, %s at %d!",
			  Rooms->Room[i].Number, infile, Line);
/* If you get an error here, it means the room designer really FUCKED UP!
 * Nevertheless, we can fudge it provided that the person didn't add the
 * SOUND definitions and forget the sector types... if this is the case,
 * An error will happen down below which will, almost certainly be log_fatal
 * and non-recoverable.
 * As it stands, we will TRY to jump inside the for() loop that scans for
 * doors and extra descriptions (and the terminating 'S') in the hopes that
 * that line is what we actually read in....
 */
	    Rooms->Room[i].                         Flags = 0;
	    Rooms->Room[i].                         Sector = SECT_FIELD;
	    Rooms->Room[i].                         MoveCost =
		SectorCosts[Rooms->Room[i].Sector];
	    Rooms->Room[i].                         Exit = (EXIT *)get_mem(1, sizeof(EXIT));
	    bzero(Rooms->Room[i].Exit, sizeof       (EXIT));
	    Rooms->Room[i].                         Exit[0].Direction = EXIT_INVALID;
	    Rooms->Room[i].                         Exit[0].Room = EXIT_INVALID;
	    Rooms->Room[i].                         Exit[0].RoomIndex = EXIT_INVALID;
	    Rooms->Room[i].                         Exit[0].Error = EXIT_UNKNOWN;
	    Rooms->Room[i].                         Extra = (extra *)get_mem(1, sizeof(extra));
	    bzero(Rooms->Room[i].Extra, sizeof      (extra));
	    j = e = Rooms->Room[i].                 ExitCount = Rooms->Room[i].ExtraCount = 0;

	    goto HolyShit;
	}
	if (Rooms->Room[i].Sector == SECT_TELEPORT) {
	    if (sscanf(tmp, " %d %d %d %d %d %d %d ", &(Rooms->Room[i].Zone),
		       &(Rooms->Room[i].Flags), &(Rooms->Room[i].Sector),
		       &(Rooms->Room[i].TeleportTime), &(Rooms->Room[i].TeleportTo),
		       &(Rooms->Room[i].TeleportLook), &(Rooms->Room[i].TeleportSector)) != 7) {
		if (Debug)
		    log_error("Bad teleport flags for Room #%d, %s at %d.",
			      Rooms->Room[i].Number, infile, Line);
/* If teleport flags are munged, we need to make it default back to a plain
 * generic sector type, so that it can still be loaded...
 */
		Rooms->Room[i].                         Sector = SECT_FIELD;
	    }
	} else if (Rooms->Room[i].Sector == SECT_WATER_NOSWIM) {
	    if (sscanf(tmp, " %d %d %d %d %d ", &(Rooms->Room[i].Zone),
		       &(Rooms->Room[i].Flags), &(Rooms->Room[i].Sector),
		       &(Rooms->Room[i].RiverSpeed), &(Rooms->Room[i].RiverDirection)) != 5) {
		Rooms->Room[i].                         RiverSpeed = 0;
		Rooms->Room[i].                         RiverDirection = -1;

		if (Debug)
		    log_error("Missing river flags for Room #%d, %s at %d.",
			      Rooms->Room[i].Number, infile, Line);
	    }
	}
	if (Rooms->Room[i].Flags & ROOM_DEATH)
	    if (Debug)
		log_error("Room #%d is a DEATH ROOM!", Rooms->Room[i].Number);

	if (Rooms->Room[i].Flags & ROOM_SOUND) {
	    Rooms->Room[i].                         SoundCount = 2;

	    for (j = 0; j < Rooms->Room[i].SoundCount; j++)
		if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
		    (!(Rooms->Room[i].SoundText[j] = my_strdup(tmp))))
		    log_fatal("Missing sound %d for Room #%d, %s at %d.",
			      j, Rooms->Room[i].Number, infile, Line);
/* additional checks should be done, but I haven't the time... let's hope the
 * wileymud people did their jobs right! <grin>
 */
	}
	Rooms->Room[i].                         Exit = (EXIT *)get_mem(1, sizeof(EXIT));
	bzero(Rooms->Room[i].Exit, sizeof       (EXIT));
	Rooms->Room[i].                         Exit[0].Direction = EXIT_INVALID;
	Rooms->Room[i].                         Exit[0].Room = EXIT_INVALID;
	Rooms->Room[i].                         Exit[0].RoomIndex = EXIT_INVALID;
	Rooms->Room[i].                         Exit[0].Error = EXIT_UNKNOWN;
	Rooms->Room[i].                         Extra = (extra *)get_mem(1, sizeof(extra));
	bzero(Rooms->Room[i].Extra, sizeof      (extra));
	Rooms->Room[i].                         MoveCost = SectorCosts[Rooms->Room[i].Sector];

	for (j = e = Rooms->Room[i].ExitCount = Rooms->Room[i].ExtraCount = 0;
	     (tmp = get_line(ifp, &Line, &Pos, 1));) {
	  HolyShit:
	    if (*tmp == 'S')
		break;
	    else if (*tmp == 'D') {
		if (sscanf(tmp + 1, "%d", &(Rooms->Room[i].Exit[j].Direction)) != 1)
		    log_fatal("Corrupt Exit in Room #%d, %s at %d.",
			      Rooms->Room[i].Number, infile, Line);
		if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
		    (!(Rooms->Room[i].Exit[j].Description = my_strdup(tmp))))
		    log_fatal("No exit description for Room #%d, %s at %d.",
			      Rooms->Room[i].Number, infile, Line);
		if (!(tmp = get_tilde_string(ifp, &Line, &Pos)))
		    log_fatal("No exit keywords for Room #%d, %s at %d.",
			      Rooms->Room[i].Number, infile, Line);
		Rooms->Room[i].                         Exit[j].Keyword =
		    make_keyword_list(tmp);
		if ((!(tmp = get_line(ifp, &Line, &Pos, 1)))
		    ||
		    (sscanf
		     (tmp, " %d %d %d ", &(Rooms->Room[i].Exit[j].Type),
		      &(Rooms->Room[i].Exit[j].KeyNumber),
		      &(Rooms->Room[i].Exit[j].Room)) != 3)) {
		    if (Debug)
			log_error("Bad exit type line in Room #%d, %s at %d.",
				  Rooms->Room[i].Number, infile, Line);
/* This most often happens when someone was planning to add an area, and
 * got one half of the links done, but now the new room numbers...
 * since our file was taken in mid-hack, right before it got zapped by
 * the Mad Cyric the Destroyer... this is not surprising.
 */
		    Rooms->Room[i].                         Exit[j].Type = EXIT_OPEN;
		    Rooms->Room[i].                         Exit[j].KeyNumber = -1;	/* no key */
		    Rooms->Room[i].                         Exit[j].Room = EXIT_INVALID;
		    Rooms->Room[i].                         Exit[j].RoomIndex = EXIT_INVALID;
		    Rooms->Room[i].                         Exit[j].Error = EXIT_NO_TARGET;
		} else {
		    Rooms->Room[i].                         Exit[j].Error = EXIT_OK;
		}
		if (Rooms->Room[i].Exit[j].Error != EXIT_UNKNOWN) {
		    j = ++Rooms->Room[i].                   ExitCount;
		    Rooms->Room[i].                         Exit = (EXIT *)
			get_more_mem((char *)Rooms->Room[i].Exit, j + 1, sizeof(EXIT));

		    bzero(&(Rooms->Room[i].Exit[j]), sizeof(EXIT));
		}
	    } else if (*tmp == 'E') {
		if (!(tmp = get_tilde_string(ifp, &Line, &Pos)))
		    log_fatal("No extra keywords for Room #%d, %s at %d.",
			      Rooms->Room[i].Number, infile, Line);
		Rooms->Room[i].                         Extra[e].Keyword =
		    make_keyword_list(tmp);
		if ((!(tmp = get_tilde_string(ifp, &Line, &Pos)))
		    || (!(Rooms->Room[i].Extra[e].Description = my_strdup(tmp))))
		    log_fatal("No extra descriptions for Room #%d, %s of %d.",
			      Rooms->Room[i].Number, infile, Line);
		e = ++Rooms->Room[i].                   ExtraCount;
		Rooms->Room[i].                         Extra = (extra *)
		    get_more_mem((char *)Rooms->Room[i].Extra, e + 1, sizeof(extra));

		bzero(&(Rooms->Room[i].Extra[e]), sizeof(extra));
	    } else
		log_fatal("Unknown line in Room #%d, %s at %d!",
			  Rooms->Room[i].Number, infile, Line);
	}
    }
    if (Verbose)
	fprintf(stderr, "Parsed %d rooms in World.\n", Rooms->Count);
    else if (!Quiet) {
	fprintf(stderr, "done.\n");
    }
    fclose(ifp);
    fix_exit_vnums(Rooms);
    check_duplicate_rooms(Rooms);
    verify_exits(Rooms);
    fix_zone_ids(Zones, Rooms);
    check_room_zone_mismatch(Zones, Rooms);
    return Rooms;
}

char                                   *room_flag_name(int Flag)
{
    switch (Flag) {
	case ROOM_DARK:
	    return "Dark";
	case ROOM_DEATH:
	    return "Death";
	case ROOM_NOMOB:
	    return "No Mobiles";
	case ROOM_INDOORS:
	    return "Indoors";
	case ROOM_NOATTACK:
	    return "No Attacks";
	case ROOM_NOSTEAL:
	    return "No Stealing";
	case ROOM_NOSUMMON:
	    return "No Summoning";
	case ROOM_NOMAGIC:
	    return "No Magic";
	case ROOM_PRIVATE:
	    return "Private";
	case ROOM_SOUND:
	    return "Has Sound";
	default:
	    return "unknown";
    }
}

char                                   *sector_name(int Sector)
{
    switch (Sector) {
	case SECT_TELEPORT:
	    return "Teleport";
	case SECT_INDOORS:
	    return "Indoors";
	case SECT_CITY:
	    return "City";
	case SECT_FIELD:
	    return "Field";
	case SECT_FOREST:
	    return "Forest";
	case SECT_HILLS:
	    return "Hills";
	case SECT_MOUNTAIN:
	    return "Mountains";
	case SECT_WATER_SWIM:
	    return "Swimmable";
	case SECT_WATER_NOSWIM:
	    return "Unswimmable";
	case SECT_AIR:
	    return "Mid-Air";
	case SECT_UNDERWATER:
	    return "Underwater";
	default:
	    return "unknown";
    }
}

char                                   *exittype_name(int Type)
{
    switch (Type) {
	case EXIT_OPEN:
	    return "an Open Passage";
	case EXIT_DOOR:
	    return "a Door";
	case EXIT_NOPICK:
	    return "an Unpickable Door";
	case EXIT_SECRET:
	    return "a Secret Door";
	case EXIT_SECRET_NOPICK:
	    return "an Unpickable Secret Door";
	case EXIT_OPEN_ALIAS:
	    return "an Aliased Passage";
	case EXIT_DOOR_ALIAS:
	    return "an Aliased Door";
	case EXIT_NOPICK_ALIAS:
	    return "an Aliased Unpickable Door";
	case EXIT_SECRET_ALIAS:
	    return "an Aliased Secret Door";
	case EXIT_SECRET_NOPICK_ALIAS:
	    return "an Aliased Unpickable Secret Door";
	default:
	    return "unknown";
    }
}

char                                   *room_flags(int Flags)
{
    static char                             tmp[MAX_PAGE_LEN];
    int                                     First = 0;

    bzero(tmp, MAX_PAGE_LEN);
    if (Flags & ROOM_DARK) {
	strcat(tmp, room_flag_name(ROOM_DARK));
	First = 1;
    }
    if (Flags & ROOM_DEATH) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_DEATH));
	First = 1;
    }
    if (Flags & ROOM_NOMOB) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_NOMOB));
	First = 1;
    }
    if (Flags & ROOM_INDOORS) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_INDOORS));
	First = 1;
    }
    if (Flags & ROOM_NOATTACK) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_NOATTACK));
	First = 1;
    }
    if (Flags & ROOM_NOSTEAL) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_NOSTEAL));
	First = 1;
    }
    if (Flags & ROOM_NOSUMMON) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_NOSUMMON));
	First = 1;
    }
    if (Flags & ROOM_NOMAGIC) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_NOMAGIC));
	First = 1;
    }
    if (Flags & ROOM_PRIVATE) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_PRIVATE));
	First = 1;
    }
    if (Flags & ROOM_SOUND) {
	if (First)
	    strcat(tmp, ", ");
	strcat(tmp, room_flag_name(ROOM_SOUND));
	First = 1;
    }
    return tmp;
}

/*
 * End of the Great Room Parser... grovelworshipbow
 */

/*
 * This routine loads a shop file (in WileyMUD DikuMUD format) and returns a
 * structure containing all the information it contained.
 */
shops                                  *load_shops(char *infile)
{
    FILE                                   *ifp;
    vnum_index                             *ShopIndex;
    shops                                  *Shops;
    char                                   *tmp;
    register int                            i,
                                            j;
    long                                    Line,
                                            Pos;

    if (!infile || !*infile)
	return NULL;
    if (!(ShopIndex = make_index(infile, NULL)))
	return NULL;
    Shops = (shops *)get_mem(1, sizeof(shops));
    bzero(Shops, sizeof(shops));
    Shops->Count = ShopIndex->Count;
    Shops->Shop = (shop *)get_mem(Shops->Count, sizeof(shop));
    bzero(Shops->Shop, Shops->Count * sizeof(shop));
    if (!Quiet) {
	fprintf(stderr, "Parsing Shop file...");
	fflush(stderr);
    }
    ifp = open_file(infile, "r");
    for (i = 0; i < Shops->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	Line = ShopIndex->VNum[i].Line;
	Pos = ShopIndex->VNum[i].Pos;
	Shops->Shop[i].Number = ShopIndex->VNum[i].Number;
	if (fseek(ifp, Pos, 0) < 0)
	    log_fatal("Cannot load Shop #%d from %s!", Shops->Shop[i].Number, infile);
	if (!(tmp = get_line(ifp, &Line, &Pos, 1)))
	    log_fatal("Cannot get vnum for Shop #%d from %s!", Shops->Shop[i].Number, infile);
	for (j = Shops->Shop[i].SellCount = 0; j < SHOP_SELLCOUNT; j++) {
	    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
		(sscanf(tmp, " %d ", &(Shops->Shop[i].Sell[j])) != 1))
		log_fatal("Cannot get item %d to sell, %s at %d.", j, infile, Line);
	    if (Shops->Shop[i].Sell[j] > -1)
		Shops->Shop[i].SellCount++;
	}
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %lf ", &(Shops->Shop[i].Selling)) != 1))
	    log_fatal("Cannot get Sell Profit Rate, %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %lf ", &(Shops->Shop[i].Buying)) != 1))
	    log_fatal("Cannot get Buy Profit Rate, %s at %d.", infile, Line);
	for (j = Shops->Shop[i].TradeCount = 0; j < SHOP_TRADECOUNT; j++) {
	    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
		(sscanf(tmp, " %d ", &(Shops->Shop[i].Trade[j])) != 1))
		log_fatal("Cannot get trade type %d to sell, %s at %d.", j, infile, Line);
	    if (Shops->Shop[i].Trade[j] > 0)
		Shops->Shop[i].TradeCount++;
	}
	Shops->Shop[i].MessageCount = SHOP_MESSAGECOUNT;
	for (j = 0; j < Shops->Shop[i].MessageCount; j++) {
	    if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
		(!(Shops->Shop[i].Message[j] = my_strdup(tmp))))
		log_fatal("Cannot get message %d, %s at %d.", j, infile, Line);
	}
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Attitude)) != 1))
	    log_fatal("Cannot get attitude (temper 0), %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Immortal)) != 1))
	    log_fatal("Cannot get immortal (temper 1), %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Keeper)) != 1))
	    log_fatal("Cannot get keeper vnum, %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Unused)) != 1))
	    log_fatal("Cannot get unused flag, %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Room)) != 1))
	    log_fatal("Cannot get room vnum, %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Open)) != 1))
	    log_fatal("Cannot get open hour, %s at %d.", infile, Line);
	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d ", &(Shops->Shop[i].Close)) != 1))
	    log_fatal("Cannot get close hour, %s at %d.", infile, Line);
	for (j = 0; j < 2; j++) {
	    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
		(sscanf(tmp, " %d ", &(Shops->Shop[i].Unused2[j])) != 1))
		log_fatal("Cannot get unused hour (1,%d), %s at %d.", j, infile, Line);
	}
    }
    fclose(ifp);
    if (!Quiet)
	fprintf(stderr, "done.\n");
    return Shops;
}

char                                   *shop_attitude_name(int Attitude)
{
    switch (Attitude) {
	case 0:
	    return "rude";
	case 1:
	    return "aloof";
	default:
	    return "unknown";
    }
}

char                                   *shop_immortal_name(int Immortal)
{
    switch (Immortal) {
	case 0:
	    return "first-strike";
	case 1:
	    return "immortal";
	default:
	    return "unknown";
    }
}

int remap_shop_vnum(shops *Shops, int VNum)
{
    register int                            i;

    for (i = 0; i < Shops->Count; i++)
	if (Shops->Shop[i].Number == VNum)
	    return i;
    return -1;
}

/*
 * General routines used for prettiness...
 */

char                                   *equip_name(int Position)
{
    switch (Position) {
	case WEAR_LIGHT:
	    return "Used as Light";
	case WEAR_FINGER_R:
	    return "Worn on Right Finger";
	case WEAR_FINGER_L:
	    return "Worn on Left Finger";
	case WEAR_NECK_1:
	    return "Worn on Neck (1)";
	case WEAR_NECK_2:
	    return "Worn on Neck (2)";
	case WEAR_BODY:
	    return "Worn on Body";
	case WEAR_HEAD:
	    return "Worn on Head";
	case WEAR_FEET:
	    return "Worn on Feet";
	case WEAR_LEGS:
	    return "Worn on Legs";
	case WEAR_HANDS:
	    return "Worn on Hands";
	case WEAR_ARMS:
	    return "Worn on Arms";
	case WEAR_SHIELD:
	    return "Used as Shield";
	case WEAR_ABOUT:
	    return "Worn About Body";
	case WEAR_WAIST:
	    return "Worn on Waist";
	case WEAR_WRIST_R:
	    return "Worn on Right Wrist";
	case WEAR_WRIST_L:
	    return "Worn on Left Wrist";
	case WIELD:
	    return "Wielded";
	case HOLD:
	    return "Held";
	case TWOH:
	    return "Wielded as Two-Handed";
	default:
	    return "unknown";
    }
}

char                                   *doorstate_name(int State)
{
    switch (State) {
	case DOOR_OPEN:
	    return "Open";
	case DOOR_CLOSED:
	    return "Closed";
	case DOOR_LOCKED:
	    return "Closed and Locked";
	default:
	    return "unknown";
    }
}

char                                   *sex_name(int State)
{
    switch (State) {
	case SEX_NEUTER:
	    return "Neuter";
	case SEX_MALE:
	    return "Male";
	case SEX_FEMALE:
	    return "Female";
	default:
	    return "unknown";
    }
}

char                                   *race_name(int Race)
{
    switch (Race) {
	case RACE_HALFBREED:
	    return "HALFBREED";
	case RACE_HUMAN:
	    return "human";
	case RACE_ELVEN:
	    return "high-elf";
	case RACE_DWARF:
	    return "dwarf";
	case RACE_HALFLING:
	    return "halfling";
	case RACE_GNOME:
	    return "gnome";
	case RACE_REPTILE:
	    return "reptile";
	case RACE_SPECIAL:
	    return "Special";
	case RACE_LYCANTH:
	    return "lycanthrope";
	case RACE_DRAGON:
	    return "dragon";
	case RACE_UNDEAD:
	    return "undead";
	case RACE_ORC:
	    return "orc";
	case RACE_INSECT:
	    return "insectoid";
	case RACE_ARACHNID:
	    return "ARACHNID";
	case RACE_DINOSAUR:
	    return "dinosaur";
	case RACE_FISH:
	    return "fish";
	case RACE_BIRD:
	    return "avis";
	case RACE_GIANT:
	    return "Giant";
	case RACE_PREDATOR:
	    return "PREDATOR";
	case RACE_PARASITE:
	    return "Parasitic";
	case RACE_SLIME:
	    return "slime";
	case RACE_DEMON:
	    return "Demonic";
	case RACE_SNAKE:
	    return "snake";
	case RACE_HERBIV:
	    return "Herbivorous";
	case RACE_TREE:
	    return "Tree";
	case RACE_VEGGIE:
	    return "Vegan";
	case RACE_ELEMENT:
	    return "Elemental";
	case RACE_PLANAR:
	    return "Planar";
	case RACE_DEVIL:
	    return "Demonic";
	case RACE_GHOST:
	    return "ghost";
	case RACE_GOBLIN:
	    return "goblin";
	case RACE_TROLL:
	    return "troll";
	case RACE_VEGMAN:
	    return "Vegman";
	case RACE_MFLAYER:
	    return "Mindflayer";
	case RACE_PRIMATE:
	    return "Primate";
	case RACE_ANIMAL:
	    return "animal";
	case RACE_FAERY:
	    return "FAERIE";
	case RACE_PLANT:
	    return "PLANT";
	default:
	    return "monster";
    }
}

char                                   *class_name(int Class)
{
    register int                            i;
    static char                             class_buffer[256];

    static char                            *class_name_list[] = {
	"mage", "cleric", "warrior",
	"rogue", "ranger", "druid"
    };

    bzero(class_buffer, 256);
    for (i = 0; i < MAX_CLASS; i++) {
	if (Class & (1 << i)) {
	    if (strlen(class_buffer))
		strcat(class_buffer, " ");
	    strcat(class_buffer, class_name_list[i]);
	}
    }
    if (!strlen(class_buffer))
	strcpy(class_buffer, "unknown");
    return class_buffer;
}

char                                   *hate_name(int Type, int Value)
{
    static char                             hate_buffer[256];

    switch (Type) {
	case HATE_SEX:
	    sprintf(hate_buffer, "sex %s's", sex_name(Value));
	    break;
	case HATE_RACE:
	    sprintf(hate_buffer, "race %s's", race_name(Value));
	    break;
	case HATE_CHAR:
	    sprintf(hate_buffer, "a specific character");
	    break;
	case HATE_CLASS:
	    sprintf(hate_buffer, "any of class %s", class_name(Value));
	    break;
	case HATE_EVIL:
	    sprintf(hate_buffer, "any more evil than %s", alignment_name(Value));
	    break;
	case HATE_GOOD:
	    sprintf(hate_buffer, "any more good than %s", alignment_name(Value));
	    break;
	case HATE_VNUM:
	    sprintf(hate_buffer, "mobile [#%d]", Value);
	    break;
	case HATE_RICH:
	    sprintf(hate_buffer, "anyone carrying more than %d gold", Value);
	    break;
	default:
	    sprintf(hate_buffer, "something unknown");
    }
    return hate_buffer;
}

char                                   *alignment_name(int Alignment)
{
    if (Alignment <= ALIGN_REALLY_VILE)
	return "Really Vile";
    else if (Alignment <= ALIGN_VILE)
	return "Vile";
    else if (Alignment <= ALIGN_VERY_EVIL)
	return "Very Evil";
    else if (Alignment <= ALIGN_EVIL)
	return "Evil";
    else if (Alignment <= ALIGN_WICKED)
	return "Wicked";
    else if (Alignment < ALIGN_NICE)
	return "Neutral";
    else if (Alignment < ALIGN_GOOD)
	return "Nice";
    else if (Alignment < ALIGN_VERY_GOOD)
	return "Good";
    else if (Alignment < ALIGN_HOLY)
	return "Very Good";
    else if (Alignment < ALIGN_REALLY_HOLY)
	return "Holy";
    else
	return "Really Holy";
}

char                                   *damage_type_name(int Type)
{
    switch (Type) {
	case FIRE_DAMAGE:
	    return "Fire";
	case COLD_DAMAGE:
	    return "Cold";
	case ELEC_DAMAGE:
	    return "Electricity";
	case BLOW_DAMAGE:
	    return "Blow";
	case ACID_DAMAGE:
	    return "Acid";
	default:
	    return "unknown";
    }
}

char                                   *immunity_name(int Imms)
{
    register int                            i;
    static char                             imm_buffer[256];

    static char                            *imm_name[] = {
	"Fire", "Cold", "Electricity", "Energy",
	"Blunt", "Pierce", "Slash", "Acid",
	"Poison", "Drain", "Sleep", "Charm",
	"Hold", "Non-Magical", "Plus-1", "Plus-2",
	"Plus-3", "Plus-4"
    };

    bzero(imm_buffer, 256);
    for (i = 0; i < MAX_IMM; i++) {
	if (Imms & (1 << i)) {
	    if (strlen(imm_buffer))
		strcat(imm_buffer, " ");
	    strcat(imm_buffer, imm_name[i]);
	}
    }
    if (!strlen(imm_buffer))
	strcpy(imm_buffer, "unknown");
    return imm_buffer;
}

char                                   *item_type_name(int Type)
{
    switch (Type) {
	case ITEM_LIGHT:
	    return "Light";
	case ITEM_SCROLL:
	    return "Scroll";
	case ITEM_WAND:
	    return "Wand";
	case ITEM_STAFF:
	    return "Staff";
	case ITEM_WEAPON:
	    return "Weapon";
	case ITEM_FIREWEAPON:
	    return "Fire-Weapon";
	case ITEM_MISSILE:
	    return "Missile";
	case ITEM_TREASURE:
	    return "Treasure";
	case ITEM_ARMOR:
	    return "Armour";
	case ITEM_POTION:
	    return "Potion";
	case ITEM_WORN:
	    return "Worn";
	case ITEM_OTHER:
	    return "Other";
	case ITEM_TRASH:
	    return "Trash";
	case ITEM_TRAP:
	    return "Trap";
	case ITEM_CONTAINER:
	    return "Container";
	case ITEM_NOTE:
	    return "Note";
	case ITEM_DRINKCON:
	    return "Drink-Container";
	case ITEM_KEY:
	    return "Key";
	case ITEM_FOOD:
	    return "Food";
	case ITEM_MONEY:
	    return "Money";
	case ITEM_PEN:
	    return "Pen";
	case ITEM_BOAT:
	    return "Boat";
	case ITEM_AUDIO:
	    return "Audio";
	case ITEM_BOARD:
	    return "Board";
	case ITEM_KENNEL:
	    return "Kennel";
	default:
	    return "unknown";
    }
}

char                                   *item_wear_name(int Type)
{
    register int                            i;
    static char                             item_buffer[256];

    static char                            *item_name[] = {
	"Taken", "worn on Finger", "worn around Neck", "worn on the Body",
	"worn on Head", "worn on Legs", "worn on Feet", "worn on Hands",
	"worn on Arms", "used as a Shield", "worn About the body", "worn around the Waiste",
	"worn on Wrist", "Wielded", "Held", "wielded Two-handed"
    };

    bzero(item_buffer, 256);
    for (i = 0; i < MAX_WEAR; i++) {
	if (Type & (1 << i)) {
	    if (strlen(item_buffer))
		strcat(item_buffer, ", ");
	    strcat(item_buffer, item_name[i]);
	}
    }
    if (!strlen(item_buffer))
	strcpy(item_buffer, "unknown");
    return item_buffer;
}

char                                   *item_flag_name(int Type)
{
    register int                            i;
    static char                             item_buffer[256];

    static char                            *item_name[] = {
	"Glow", "Hum", "Metal", "Mineral",
	"Organic", "Invisible", "Magical", "Undroppable",
	"Blessed", "Anti-Good", "Anti-Evil", "Anti-Neutral",
	"Anti-Cleric", "Anti-Mage", "Anti-Thief", "Anti-Fighter",
	"Anti-Ranger", "Parishable"
    };

    bzero(item_buffer, 256);
    for (i = 0; i < MAX_ITEM_FLAGS + 1; i++) {
	if (Type & (1 << i)) {
	    if (strlen(item_buffer))
		strcat(item_buffer, " ");
	    strcat(item_buffer, item_name[i]);
	}
    }
    if (!strlen(item_buffer))
	strcpy(item_buffer, "unknown");
    return item_buffer;
}

char                                   *liquid_name(int Type)
{
    switch (Type) {
	case LIQ_WATER:
	    return "Water";
	case LIQ_BEER:
	    return "Beer";
	case LIQ_WINE:
	    return "Wine";
	case LIQ_ALE:
	    return "Ale";
	case LIQ_DARKALE:
	    return "Dark-Ale";
	case LIQ_WHISKY:
	    return "Whisky";
	case LIQ_LEMONADE:
	    return "Lemonaide";
	case LIQ_FIREBRT:
	    return "Firebreather";
	case LIQ_LOCALSPC:
	    return "Local-Speciality";
	case LIQ_SLIME:
	    return "Slime";
	case LIQ_MILK:
	    return "Milk";
	case LIQ_TEA:
	    return "Tea";
	case LIQ_COFFE:
	    return "Coffee";
	case LIQ_BLOOD:
	    return "Blood";
	case LIQ_SALTWATER:
	    return "Salt-Water";
	case LIQ_COKE:
	    return "Coke";
	default:
	    return "unknown";
    }
}

char                                   *item_equip_name(int Position)
{
    switch (Position) {
	case WEAR_LIGHT:
	    return "Used as Light";
	case WEAR_FINGER_R:
	    return "Worn on Right Finger";
	case WEAR_FINGER_L:
	    return "Worn on Left Finger";
	case WEAR_NECK_1:
	    return "Worn on Neck (1)";
	case WEAR_NECK_2:
	    return "Worn on Neck (2)";
	case WEAR_BODY:
	    return "Worn on Body";
	case WEAR_HEAD:
	    return "Worn on Head";
	case WEAR_FEET:
	    return "Worn on Feet";
	case WEAR_LEGS:
	    return "Worn on Legs";
	case WEAR_HANDS:
	    return "Worn on Hands";
	case WEAR_ARMS:
	    return "Worn on Arms";
	case WEAR_SHIELD:
	    return "Used as Shield";
	case WEAR_ABOUT:
	    return "Worn About Body";
	case WEAR_WAIST:
	    return "Worn on Waist";
	case WEAR_WRIST_R:
	    return "Worn on Right Wrist";
	case WEAR_WRIST_L:
	    return "Worn on Left Wrist";
	case WIELD:
	    return "Wielded";
	case HOLD:
	    return "Held";
	case TWOH:
	    return "Wielded as Two-Handed";
	default:
	    return "unknown";
    }
}

char                                   *container_closeable(int Value)
{
    register int                            i;
    static char                             cont_buffer[256];

    static char                            *cont_name[] = {
	"Closeable", "Pickproof", "Closed", "Locked"
    };

    bzero(cont_buffer, 256);
    for (i = 0; i < MAX_CONT_CLOSE; i++) {
	if (Value & (1 << i)) {
	    if (strlen(cont_buffer))
		strcat(cont_buffer, " ");
	    strcat(cont_buffer, cont_name[i]);
	}
    }
    if (!strlen(cont_buffer))
	strcpy(cont_buffer, "unknown");
    return cont_buffer;
}

char                                   *affected_by_name(int Flag)
{
    register int                            i;
    static char                             a_buffer[256];

    static char                            *a_name[] = {
	"Blind", "Invisible", "Detect-Evil", "Detect-Invisible",
	"Detect-Magic", "Sense-Life", "Silence", "Sanctuary",
	"Group", "MISSING", "Curse", "Flying",
	"Poison", "Protection-From-Evil", "Paralysis", "Infravision",
	"Water-Breathing", "Sleep", "Drug-Free", "Sneak",
	"Hide", "Fear", "Charm", "Follow",
	"UNDEF-1", "True-Sight", "Scrying", "Fireshield",
	"Ride", "UNDEF-6", "UNDEF-7", "UNDEF-8"
    };

    bzero(a_buffer, 256);
    for (i = 0; i < MAX_AFFECTED_BY; i++) {
	if (Flag & (1 << i)) {
	    if (strlen(a_buffer))
		strcat(a_buffer, " ");
	    strcat(a_buffer, a_name[i]);
	}
    }
    if (!strlen(a_buffer))
	strcpy(a_buffer, "unknown");
    return a_buffer;
}

char                                   *apply_name(int Flag)
{
    switch (Flag) {
	case APPLY_NONE:
	    return "None";
	case APPLY_STR:
	    return "Strength";
	case APPLY_DEX:
	    return "Dexterity";
	case APPLY_INT:
	    return "Intelligence";
	case APPLY_WIS:
	    return "Wisdom";
	case APPLY_CON:
	    return "Constitution";
	case APPLY_SEX:
	    return "Sex";
	case APPLY_CLASS:
	    return "Class";
	case APPLY_LEVEL:
	    return "Level";
	case APPLY_AGE:
	    return "Age";
	case APPLY_CHAR_WEIGHT:
	    return "Weight";
	case APPLY_CHAR_HEIGHT:
	    return "Height";
	case APPLY_MANA:
	    return "Mana";
	case APPLY_HIT:
	    return "Hit-Points";
	case APPLY_MOVE:
	    return "Move";
	case APPLY_GOLD:
	    return "Gold";
	case APPLY_EXP:
	    return "Experience";
	case APPLY_AC:
	    return "Armour-Class";
	case APPLY_HITROLL:
	    return "To-Hit";
	case APPLY_DAMROLL:
	    return "Damage";
	case APPLY_SAVING_PARA:
	    return "Save-vs-Paralysis";
	case APPLY_SAVING_ROD:
	    return "Save-vs-Rod";
	case APPLY_SAVING_PETRI:
	    return "Save-vs-Petrification";
	case APPLY_SAVING_BREATH:
	    return "Save-vs-Breath-Weapons";
	case APPLY_SAVING_SPELL:
	    return "Save-vs-Spell";
	case APPLY_SAVE_ALL:
	    return "Saving-Throws";
	case APPLY_IMMUNE:
	    return "Resistance";
	case APPLY_SUSC:
	    return "Susceptability";
	case APPLY_M_IMMUNE:
	    return "Immunity";
	case APPLY_SPELL:
	    return "Spell";
	case APPLY_WEAPON_SPELL:
	    return "Weapon-Spell";
	case APPLY_EAT_SPELL:
	    return "Eat-Spell";
	case APPLY_BACKSTAB:
	    return "Backstab";
	case APPLY_KICK:
	    return "Kick";
	case APPLY_SNEAK:
	    return "Sneak";
	case APPLY_HIDE:
	    return "Hide";
	case APPLY_BASH:
	    return "Bash";
	case APPLY_PICK:
	    return "Picklock";
	case APPLY_STEAL:
	    return "Steal";
	case APPLY_TRACK:
	    return "Track";
	case APPLY_HITNDAM:
	    return "To-Hit-and-Damage";
	default:
	    return "unknown";
    }
}

char                                   *position_name(int Flag)
{
    switch (Flag) {
	case POSITION_DEAD:
	    return "Dead";
	case POSITION_MORTALLYW:
	    return "Mortally-Wounded";
	case POSITION_INCAP:
	    return "Incapacitated";
	case POSITION_STUNNED:
	    return "Stunned";
	case POSITION_SLEEPING:
	    return "Sleeping";
	case POSITION_RESTING:
	    return "Resting";
	case POSITION_SITTING:
	    return "Sitting";
	case POSITION_FIGHTING:
	    return "Fighting";
	case POSITION_STANDING:
	    return "Standing";
	case POSITION_MOUNTED:
	    return "Mounted";
	default:
	    return "unknown";
    }
}

char                                   *act_name(int Flag)
{
    register int                            i;
    static char                             a_buffer[256];

    static char                            *a_name[] = {
	"Special-Function", "Sentinel", "Scavenger", "IsNPC",
	"Nice-Thief", "Aggressive", "Stay-Zone", "Wimpy",
	"Annoying", "Hateful", "Afraid", "Immortal",
	"Hunting", "Deadly", "Polymorph-Self", "Polymorph-Other",
	"Guardian", "Use-Items", "Fighter-Moves", "Provide-Food",
	"Protector", "Mount", "Switch"
    };

    bzero(a_buffer, 256);
    for (i = 0; i < MAX_ACT; i++) {
	if (Flag & (1 << i)) {
	    if (strlen(a_buffer))
		strcat(a_buffer, " ");
	    strcat(a_buffer, a_name[i]);
	}
    }
    if (!strlen(a_buffer))
	strcpy(a_buffer, "unknown");
    return a_buffer;
}

int remap_obj_vnum(objects *Objects, int VNum)
{
    register int                            i;

    for (i = 0; i < Objects->Count; i++)
	if (Objects->Object[i].Number == VNum)
	    return i;
    return -1;
}

char                                   *obj_name(objects *Objects, int VNum)
{
    int                                     i;

    if ((i = remap_obj_vnum(Objects, VNum)) != -1)
	return Objects->Object[i].ShortDesc;
    else
	return "a non-existant object";
}

void check_duplicate_objs(objects *Objects)
{
    register int                            i,
                                            tmp;

    if (!Quiet) {
	fprintf(stderr, "Checking for duplicate object vnums...");
	fflush(stderr);
    }
    for (i = 0; i < Objects->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	tmp = Objects->Object[i].Number;
	Objects->Object[i].Number = -1;
	if (remap_obj_vnum(Objects, tmp) >= 0)
	    if (Debug)
		log_error("OBJECT [#%d] is DUPLICATED!!!", tmp);
	Objects->Object[i].Number = tmp;
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void set_obj_zones(zones *Zones, objects *Objects)
{
    register int                            i,
                                            j,
                                            CorrectZone;

    if (!Quiet) {
	fprintf(stderr, "Setting Zone id tags...");
	fflush(stderr);
    }
    for (i = 0; i < Objects->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	CorrectZone = -1;
	for (j = 0; j < Zones->Count; j++)
	    if (Objects->Object[i].Number <= Zones->Zone[j].Top)
		if (Objects->Object[i].Number >= ((j > 0) ? Zones->Zone[j - 1].Top + 1 : 0)) {
		    CorrectZone = Zones->Zone[j].Number;
		    break;
		}
	if (CorrectZone == -1) {
	    if (Verbose)
		log_error("Holy BatTurds!  I have NO IDEA what zone this object [#%d] "
			  "belongs to!\nPutting it in Zone %d...\n",
			  Objects->Object[i].Number, Zones->Zone[0].Number);
	    Objects->Object[i].Zone = Zones->Zone[0].Number;
	} else {
	    Objects->Object[i].Zone = CorrectZone;
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void check_object_zone_mismatch(zones *Zones, objects *Objects)
{
    register int                            i,
                                            CorrectZone;

    if (!Quiet) {
	fprintf(stderr, "Verifying proper Zone id tags...");
	fflush(stderr);
    }
    for (i = 0; i < Objects->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	CorrectZone = Objects->Object[i].Number / 100;
	if (Objects->Object[i].Zone != CorrectZone) {
	    log_error("Improper Zone ID of [#%d] for object \"%s\" [#%d],\n"
		      "Should belong to Zone [#%d].\n",
		      Objects->Object[i].Zone, Objects->Object[i].Name,
		      Objects->Object[i].Number, CorrectZone);
	    /*
	     * Objects->Object[i].Zone= CorrectZone; 
	     */
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

/*
 * This routine loads the object file from WileyMUD III format.
 */
objects                                *load_objects(char *infile, zones *Zones)
{
    FILE                                   *ifp;
    vnum_index                             *ObjIndex;
    objects                                *Objects;
    char                                   *tmp;	       /* , tmp2[MAX_LINE_LEN], *tmp3; */
    register int                            i,
                                            j,
                                            e;
    long                                    Line,
                                            Pos;

    if (!infile || !*infile)
	return NULL;
    if (!(ObjIndex = make_index(infile, NULL)))
	return NULL;
    Objects = (objects *)get_mem(1, sizeof(objects));
    bzero(Objects, sizeof(objects));
    Objects->Count = ObjIndex->Count;
    Objects->Object = (object *)get_mem(Objects->Count, sizeof(object));
    bzero(Objects->Object, Objects->Count * sizeof(object));
    ifp = open_file(infile, "r");

    if (Verbose)
	fprintf(stderr, "Parsing Object file...\n");
    else if (!Quiet) {
	fprintf(stderr, "Parsing Object file...");
	fflush(stderr);
    }

    for (i = 0; i < Objects->Count; i++) {
	Line = ObjIndex->VNum[i].Line;
	Pos = ObjIndex->VNum[i].Pos;
	Objects->Object[i].Number = ObjIndex->VNum[i].Number;
	if (fseek(ifp, Pos, 0) < 0)
	    log_fatal("Cannot load Object $%d from %s!", Objects->Object[i].Number, infile);
	if (!(tmp = get_line(ifp, &Line, &Pos, 1)))
	    log_fatal("Cannot get vnum for Object #%d from %s!",
		      Objects->Object[i].Number, infile);
	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Objects->Object[i].Name = my_strdup(tmp))))
	    log_fatal("Cannot get name for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	if (Verbose)
	    fprintf(stderr, "  (%d) Parsing \"%s\"[#%d]...\n", i,
		    Objects->Object[i].Name, Objects->Object[i].Number);
	else if (!Quiet)
	    spin(stderr);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Objects->Object[i].ShortDesc = my_strdup(tmp))))
	    log_fatal("Cannot get short description for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Objects->Object[i].Description = my_strdup(tmp))))
	    log_fatal("Cannot get description for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Objects->Object[i].ActionDesc = my_strdup(tmp))))
	    log_fatal("Cannot get action description for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d %d %d ", &(Objects->Object[i].Type),
		    &(Objects->Object[i].Flags.Extra), &(Objects->Object[i].Flags.Wear)) != 3))
	    log_fatal("Cannot get main flags for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d %d %d %d ", &(Objects->Object[i].Flags.Value[0]),
		    &(Objects->Object[i].Flags.Value[1]), &(Objects->Object[i].Flags.Value[2]),
		    &(Objects->Object[i].Flags.Value[3])) != 4))
	    log_fatal("Cannot get value flags for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    (sscanf(tmp, " %d %d %d ", &(Objects->Object[i].Weight),
		    &(Objects->Object[i].Value), &(Objects->Object[i].Rent)) != 3))
	    log_fatal("Cannot get value flags for Object #%d, %s at %d.",
		      Objects->Object[i].Number, infile, Line);

	Objects->Object[i].Affect = (obj_affect *)get_mem(1, sizeof(obj_affect));
	bzero(Objects->Object[i].Affect, sizeof(obj_affect));
	Objects->Object[i].Affect[0].location = 0;
	Objects->Object[i].Affect[0].modifier = 0;

	Objects->Object[i].Extra = (extra *)get_mem(1, sizeof(extra));
	bzero(Objects->Object[i].Extra, sizeof(extra));

	for (j = e = Objects->Object[i].AffectCount = Objects->Object[i].ExtraCount = 0;
	     (tmp = get_line(ifp, &Line, &Pos, 1));) {
	    if (*tmp == '#')
		break;
	    /*
	     * else if(*tmp == '~') continue; 
	     */
	    else if (*tmp == '$')
		continue;
	    else if (*tmp == 'A') {
		if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
		    (sscanf(tmp, " %d %d ", &(Objects->Object[i].Affect[j].location),
			    &(Objects->Object[i].Affect[j].modifier)) != 2))
		    log_fatal("Cannot get affect flags for Object #%d, %s at %d.",
			      Objects->Object[i].Number, infile, Line);
		j = ++Objects->Object[i].AffectCount;
		Objects->Object[i].Affect = (obj_affect *)
		    get_more_mem((char *)Objects->Object[i].Affect, j + 1, sizeof(obj_affect));
		bzero(&(Objects->Object[i].Affect[j]), sizeof(obj_affect));
	    } else if (*tmp == 'E') {
		if (!(tmp = get_tilde_string(ifp, &Line, &Pos)))
		    log_fatal("No extra keywords for Object #%d, %s at %d.",
			      Objects->Object[i].Number, infile, Line);
		Objects->Object[i].Extra[e].Keyword = make_keyword_list(tmp);
		if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
		    (!(Objects->Object[i].Extra[e].Description = my_strdup(tmp))))
		    log_fatal("No extra descriptions for Object #%d, %s of %d.",
			      Objects->Object[i].Number, infile, Line);
		e = ++Objects->Object[i].ExtraCount;
		Objects->Object[i].Extra = (extra *)
		    get_more_mem((char *)Objects->Object[i].Extra, e + 1, sizeof(extra));
		bzero(&(Objects->Object[i].Extra[e]), sizeof(extra));
	    } else
		log_fatal("Unknown line in Object #%d, %s at %d!",
			  Objects->Object[i].Number, infile, Line);
	}
    }
    if (Verbose)
	fprintf(stderr, "Parsed %d objects in World.\n", Objects->Count);
    else if (!Quiet) {
	fprintf(stderr, "done.\n");
    }
    fclose(ifp);
    check_duplicate_objs(Objects);
    set_obj_zones(Zones, Objects);
    check_object_zone_mismatch(Zones, Objects);
    return Objects;
}

char                                   *spell_name(int Spell)
{
    register int                            i;
    static int                              assigned = 0;
    static char                            *spell[MAX_SKILLS];

    if (!assigned) {
	bzero(spell, MAX_SKILLS * sizeof(char *));

	ASSIGN_SPELL(SKILL_APRAISE, 0, 1, "appraise", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 2, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BACKSTAB, 0, 1, "backstab", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BANDAGE, 0, 1, "bandage", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 1, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BARE_HAND, 0, 1, "barehand", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 1, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BARTER, 0, 0, "barter", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BASH, 0, 1, "bash", NULL, 0, 100, 100, TAR_IGNORE, POSITION_STANDING,
		     LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, 1, LOKI);
	ASSIGN_SPELL(SKILL_BASH_W_SHIELD, 0, 0, "shield bash", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BLIND_FIGHTING, 0, 0, "blind fighting", NULL, 0, 100, 100,
		     TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI,
		     LOKI, LOKI);
	ASSIGN_SPELL(SKILL_BREW, 0, 0, "brewing", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_DETECT_NOISE, 0, 0, "hear noise", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_DISARM, 0, 1, "disarm", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, 1, LOKI);
	ASSIGN_SPELL(SKILL_DISARM_TRAP, 0, 0, "disarm trap", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_DODGE, 0, 0, "dodge", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_DOOR_BASH, 0, 1, "doorbash", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, 1, LOKI);
	ASSIGN_SPELL(SKILL_ENDURANCE, 0, 1, "endurance", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 3, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_FIND_TRAP, 0, 1, "locate trap", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_HIDE, 0, 1, "hide", NULL, 0, 100, 100, TAR_IGNORE, POSITION_STANDING,
		     LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, 1, LOKI);
	ASSIGN_SPELL(SKILL_KICK, 0, 1, "kick", NULL, 0, 100, 100, TAR_IGNORE, POSITION_STANDING,
		     LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_KNOCK_OUT, 0, 0, "knockout", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_MEDITATION, 0, 1, "meditation", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 7, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_PARRY, 0, 0, "parry", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_PEER, 0, 1, "peer", NULL, 0, 100, 100, TAR_IGNORE, POSITION_STANDING,
		     LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, 1, LOKI);
	ASSIGN_SPELL(SKILL_PICK_LOCK, 0, 1, "pick lock", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_PUNCH, 0, 1, "punch", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 2, CLASS_ALL, LOKI, LOKI, 1, LOKI, 1, LOKI);
	ASSIGN_SPELL(SKILL_READ_MAGIC, 0, 0, "read magic", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 3, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_RESCUE, 0, 1, "rescue", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, 1, LOKI);
	ASSIGN_SPELL(SKILL_RIDE, 0, 1, "riding", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 1, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SCRIBE, 0, 0, "scribe", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SEARCH, 0, 1, "search", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, 1, LOKI);
	ASSIGN_SPELL(SKILL_SNEAK, 0, 1, "sneak", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, 1, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_BLUDGE, 0, 1, "bludgeon spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_CLEAVE, 0, 1, "cleave spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_CRUSH, 0, 1, "crush spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_PIERCE, 0, 1, "pierce spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_SLASH, 0, 1, "slash spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_SMASH, 0, 1, "smash spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_SMITE, 0, 1, "smite spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_STAB, 0, 1, "stab spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPEC_WHIP, 0, 1, "whip spec", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, 1, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SPELLCRAFT, 0, 1, "spellcraft", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 7, CLASS_MAGICAL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_STEAL, 0, 1, "steal", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, 1, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_SWIMMING, 0, 1, "swimming", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 1, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_TRACK, 0, 1, "track", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 3, CLASS_SNEAK, LOKI, LOKI, LOKI, 1, 1, LOKI);
	ASSIGN_SPELL(SKILL_TWO_HANDED, 0, 1, "two handed", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, 5, CLASS_FIGHTER, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SKILL_TWO_WEAPON, 0, 0, "dual wield", NULL, 0, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MANA, 0, 0, "MANA", NULL, 12, 100, 100, TAR_IGNORE,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_ACID_BLAST, 1, 0, "acid blast", cast_acid_blast, 24, 15, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 7, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_AID, 1, 0, "aid", cast_aid, 12, 15, 50, TAR_CHAR_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 10, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_ANIMATE_DEAD, 1, 0, "animate dead", cast_animate_dead, 24, 15, 50,
		     TAR_OBJ_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 10, 7, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_ARMOR, 1, 0, "armour", cast_armor, 12, 5, 50, TAR_CHAR_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, 4, 1, LOKI, LOKI, 10, LOKI);
	ASSIGN_SPELL(SPELL_ASTRAL_WALK, 1, 0, "astral walk", cast_astral_walk, 12, 33, 50,
		     TAR_CHAR_WORLD, POSITION_STANDING, LOKI, CLASS_ALL, 21, 18, LOKI, LOKI,
		     LOKI, LOKI);
	ASSIGN_SPELL(SPELL_BLESS, 1, 0, "bless", cast_bless, 12, 5, 50,
		     TAR_OBJ_INV | TAR_OBJ_EQUIP | TAR_CHAR_ROOM, POSITION_STANDING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 1, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_BLINDNESS, 1, 0, "blindness", cast_blindness, 24, 5, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 8, 6, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_BURNING_HANDS, 1, 0, "burning hands", cast_burning_hands, 24, 30, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 5,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CACAODEMON, 1, 0, "cacaodemon", cast_cacaodemon, 24, 50, 100,
		     TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 30, 30, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_CALL_LIGHTNING, 1, 0, "call lightning", cast_call_lightning, 36, 15,
		     50, TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 15, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CALM, 1, 0, "calm", cast_calm, 24, 15, 50, TAR_CHAR_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, 4, 2, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CAUSE_CRITICAL, 1, 0, "cause critical", cast_cause_critic, 18, 11,
		     50, TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 9, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CAUSE_LIGHT, 1, 0, "cause light", cast_cause_light, 12, 8, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI, CLASS_ALL,
		     LOW_IMMORTAL, 1, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CAUSE_SERIOUS, 1, 0, "cause serious", cast_cause_serious, 12, 9, 50,
		     TAR_CHAR_ROOM | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 30, 7,
		     LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CHARM_MONSTER, 1, 0, "charm monster", cast_charm_monster, 18, 5, 50,
		     TAR_CHAR_ROOM | TAR_VIOLENT, POSITION_STANDING, LOKI, CLASS_ALL, 8, 8,
		     LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CHARM_PERSON, 1, 0, "charm person", cast_charm_person, 12, 5, 50,
		     TAR_CHAR_ROOM | TAR_SELF_NONO | TAR_FIGHT_VICT | TAR_VIOLENT,
		     POSITION_STANDING, LOKI, CLASS_ALL, 12, 12, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CHILL_TOUCH, 1, 0, "chill touch", cast_chill_touch, 12, 15, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 3, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CLONE, 1, 0, "clone", cast_clone, 48, 50, 100, TAR_CHAR_WORLD,
		     POSITION_STANDING, LOKI, CLASS_ALL, 25, 48, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_COLOUR_SPRAY, 1, 0, "colour spray", cast_colour_spray, 24, 15, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 11,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CONE_OF_COLD, 1, 0, "cone of cold", cast_cone_of_cold, 24, 15, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 11,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CONJURE_ELEMENTAL, 1, 0, "conjure elemental", cast_conjure_elemental,
		     24, 30, 100, TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 16, 14, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CONTROL_WEATHER, 1, 0, "control weather", cast_control_weather, 36,
		     25, 50, TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 10, 13, LOKI, LOKI,
		     LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CONT_LIGHT, 1, 0, "continual light", cast_cont_light, 24, 10, 50,
		     TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 3, 4, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_CREATE_FOOD, 1, 0, "create food", cast_create_food, 12, 5, 50,
		     TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 3, LOKI,
		     LOKI, 11, LOKI);
	ASSIGN_SPELL(SPELL_CREATE_WATER, 1, 0, "create water", cast_create_water, 12, 5, 50,
		     TAR_OBJ_INV | TAR_OBJ_EQUIP, POSITION_STANDING, LOKI, CLASS_ALL,
		     LOW_IMMORTAL, 2, LOKI, LOKI, 10, LOKI);
	ASSIGN_SPELL(SPELL_CURE_BLIND, 1, 0, "cure blindness", cast_cure_blind, 12, 5, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 4, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CURE_CRITIC, 1, 0, "cure critical", cast_cure_critic, 12, 11, 50,
		     TAR_CHAR_ROOM, POSITION_FIGHTING, LOKI, CLASS_ALL, LOW_IMMORTAL, 9, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_CURE_LIGHT, 1, 0, "cure light", cast_cure_light, 12, 5, 50,
		     TAR_CHAR_ROOM, POSITION_FIGHTING, LOKI, CLASS_ALL, LOW_IMMORTAL, 1, LOKI,
		     LOKI, 10, LOKI);
	ASSIGN_SPELL(SPELL_CURE_SERIOUS, 1, 0, "cure serious", cast_cure_serious, 12, 9, 50,
		     TAR_CHAR_ROOM, POSITION_FIGHTING, LOKI, CLASS_ALL, 30, 7, LOKI, LOKI, 15,
		     LOKI);
	ASSIGN_SPELL(SPELL_CURSE, 1, 0, "curse", cast_curse, 24, 20, 50,
		     TAR_CHAR_ROOM | TAR_OBJ_ROOM | TAR_OBJ_INV | TAR_OBJ_EQUIP | TAR_FIGHT_VICT
		     | TAR_VIOLENT, POSITION_STANDING, LOKI, CLASS_ALL, 12, 12, LOKI, LOKI,
		     LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DETECT_EVIL, 1, 0, "detect evil", cast_detect_evil, 12, 5, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 1, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DETECT_INVISIBLE, 1, 0, "detect invisible", cast_detect_invisibility,
		     12, 5, 50, TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 2, 5, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DETECT_MAGIC, 1, 0, "detect magic", cast_detect_magic, 12, 5, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 1, 3, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_DETECT_POISON, 1, 0, "detect poison", cast_detect_poison, 12, 5, 50,
		     TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_EQUIP, POSITION_STANDING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 2, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DISPEL_EVIL, 1, 0, "dispel evil", cast_dispel_evil, 36, 100, 100,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI, CLASS_ALL,
		     LOW_IMMORTAL, 12, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DISPEL_GOOD, 1, 0, "dispel good", cast_dispel_good, 36, 100, 100,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI, CLASS_ALL,
		     LOW_IMMORTAL, 12, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DISPEL_MAGIC, 1, 0, "dispel magic", cast_dispel_magic, 12, 15, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI, CLASS_ALL, 6, 6,
		     LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_DRAGON_BREATH, 0, 0, "DRAGON BREATH", cast_dragon_breath, 0, 100,
		     100, TAR_IGNORE | TAR_VIOLENT, POSITION_STANDING, LOKI, CLASS_ALL, LOKI,
		     LOKI, LOKI, LOKI, LOKI, LOKI);
#if 1
	ASSIGN_SPELL(SPELL_EARTHQUAKE, 1, 0, "earthquake", cast_earthquake, 24, 15, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, LOW_IMMORTAL,
		     8, LOKI, LOKI, LOKI, LOKI);
#else
	ASSIGN_SPELL(SPELL_EARTHQUAKE, 1, 0, "earthquake", cast_new_earthquake, 24, 15, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, LOW_IMMORTAL,
		     8, LOKI, LOKI, LOKI, LOKI);
#endif
	ASSIGN_SPELL(SPELL_ENCHANT_WEAPON, 1, 0, "enchant weapon", cast_enchant_weapon, 48, 100,
		     100, TAR_OBJ_INV | TAR_OBJ_EQUIP, POSITION_STANDING, LOKI, CLASS_ALL, 9,
		     25, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_ENERGY_DRAIN, 1, 0, "energy drain", cast_energy_drain, 36, 35, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 17, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_FAERIE_FIRE, 1, 0, "faerie fire", cast_faerie_fire, 12, 10, 50,
		     TAR_CHAR_ROOM | TAR_SELF_NONO, POSITION_STANDING, LOKI, CLASS_ALL, 5, 3,
		     LOKI, LOKI, 11, LOKI);
	ASSIGN_SPELL(SPELL_FAERIE_FOG, 1, 0, "faerie fog", cast_faerie_fog, 24, 20, 50,
		     TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 13, 10, LOKI, LOKI, 14,
		     LOKI);
	ASSIGN_SPELL(SPELL_FEAR, 1, 0, "fear", cast_fear, 12, 15, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 8, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_FIREBALL, 1, 0, "fireball", cast_fireball, 36, 15, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 15,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_FIRESHIELD, 1, 0, "fireshield", cast_fireshield, 24, 40, 50,
		     TAR_SELF_ONLY | TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 20, 19,
		     LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_FLAMESTRIKE, 1, 0, "flamestrike", cast_flamestrike, 24, 15, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 11, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_FLY, 1, 0, "fly", cast_flying, 12, 15, 50, TAR_CHAR_ROOM,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, 3, 14, LOKI, LOKI, 18, LOKI);
	ASSIGN_SPELL(SPELL_FLY_GROUP, 1, 0, "group fly", cast_fly_group, 18, 30, 50, TAR_IGNORE,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, 8, 22, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_GOODBERRY, 1, 0, "goodberry", cast_goodberry, 12, 40, 80, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, 40, LOKI, LOKI, 25, LOKI);
	ASSIGN_SPELL(SPELL_HARM, 1, 0, "harm", cast_harm, 36, 50, 100,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 17, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_HEAL, 1, 0, "heal", cast_heal, 18, 50, 100, TAR_CHAR_ROOM,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, LOW_IMMORTAL, 17, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_ICE_STORM, 1, 0, "ice storm", cast_ice_storm, 12, 15, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 7,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_IDENTIFY, 0, 0, "IDENTIFY", cast_identify, 1, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, LOKI, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_INFRAVISION, 1, 0, "infravision", cast_infravision, 12, 7, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 5, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_INVISIBLE, 1, 0, "invisibility", cast_invisibility, 12, 5, 50,
		     TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM | TAR_OBJ_EQUIP,
		     POSITION_STANDING, LOKI, CLASS_ALL, 4, LOW_IMMORTAL, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_KNOCK, 1, 0, "knock", cast_knock, 12, 10, 50, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, 3, LOW_IMMORTAL, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_KNOW_ALIGNMENT, 1, 0, "know alignment", cast_know_alignment, 12, 10,
		     50, TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI, CLASS_ALL, 4,
		     3, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_LIGHT, 1, 0, "create light", cast_light, 12, 5, 50, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, 1, 2, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_LIGHTNING_BOLT, 1, 0, "lightning bolt", cast_lightning_bolt, 24, 15,
		     50, TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 9, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_LOCATE_OBJECT, 1, 0, "locate object", cast_locate_object, 12, 20, 50,
		     TAR_NAME, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 4, LOKI, LOKI,
		     LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MAGIC_MISSILE, 1, 0, "magic missile", cast_magic_missile, 12, 10, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 1, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_METEOR_SWARM, 1, 0, "meteor swarm", cast_meteor_swarm, 24, 50, 50,
		     TAR_IGNORE | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL, 20,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MINOR_CREATE, 1, 0, "minor creation", cast_minor_creation, 24, 30,
		     50, TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 8, 14, LOKI, LOKI,
		     LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_1, 1, 0, "monsum one", cast_mon_sum1, 24, 10, 50, TAR_IGNORE,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, 5, LOW_IMMORTAL, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_2, 1, 0, "monsum two", cast_mon_sum2, 24, 12, 50, TAR_IGNORE,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, 7, LOW_IMMORTAL, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_3, 1, 0, "monsum three", cast_mon_sum3, 24, 15, 50,
		     TAR_IGNORE, POSITION_FIGHTING, LOKI, CLASS_ALL, 9, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_4, 1, 0, "monsum four", cast_mon_sum4, 24, 17, 50,
		     TAR_IGNORE, POSITION_FIGHTING, LOKI, CLASS_ALL, 11, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_5, 1, 0, "monsum five", cast_mon_sum5, 24, 20, 50,
		     TAR_IGNORE, POSITION_FIGHTING, LOKI, CLASS_ALL, 13, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_6, 1, 0, "monsum six", cast_mon_sum6, 24, 22, 50, TAR_IGNORE,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, 15, LOW_IMMORTAL, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_MON_SUM_7, 1, 0, "monsum seven", cast_mon_sum7, 24, 25, 50,
		     TAR_IGNORE, POSITION_STANDING, LOKI, CLASS_ALL, 17, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_PARALYSIS, 1, 0, "paralyze", cast_paralyze, 36, 40, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 15, 15, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_POISON, 1, 0, "poison", cast_poison, 24, 10, 50,
		     TAR_CHAR_ROOM | TAR_SELF_NONO | TAR_OBJ_INV | TAR_OBJ_EQUIP | TAR_OBJ_ROOM
		     | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI, CLASS_ALL,
		     LOW_IMMORTAL, 8, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_POLY_SELF, 1, 0, "polymorph self", cast_poly_self, 12, 30, 50,
		     TAR_IGNORE, POSITION_FIGHTING, LOKI, CLASS_ALL, 8, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_PROTECT_FROM_EVIL, 1, 0, "protection from evil",
		     cast_protection_from_evil, 12, 5, 50, TAR_CHAR_ROOM, POSITION_STANDING,
		     LOKI, CLASS_ALL, LOW_IMMORTAL, 6, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_REFRESH, 1, 0, "refresh", cast_refresh, 12, 5, 50, TAR_CHAR_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, 3, 2, LOKI, LOKI, 11, LOKI);
	ASSIGN_SPELL(SPELL_REMOVE_CURSE, 1, 0, "remove curse", cast_remove_curse, 12, 5, 50,
		     TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_EQUIP | TAR_OBJ_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 7, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_REMOVE_PARALYSIS, 1, 0, "remove paralysis", cast_remove_paralysis,
		     12, 10, 50, TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 4, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_REMOVE_POISON, 1, 0, "remove poison", cast_remove_poison, 12, 5, 50,
		     TAR_CHAR_ROOM | TAR_OBJ_INV | TAR_OBJ_ROOM, POSITION_STANDING, LOKI,
		     CLASS_ALL, LOW_IMMORTAL, 5, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SANCTUARY, 1, 0, "sanctuary", cast_sanctuary, 36, 50, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 19, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SECOND_WIND, 1, 0, "second wind", cast_second_wind, 12, 5, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 12, 6, LOKI, LOKI, 16,
		     LOKI);
	ASSIGN_SPELL(SPELL_SENSE_LIFE, 1, 0, "sense life", cast_sense_life, 12, 5, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 7, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SHELTER, 1, 0, "shelter", cast_shelter, 12, 100, 100, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, 10, 10, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SHIELD, 1, 0, "shield", cast_shield, 24, 15, 50, TAR_CHAR_ROOM,
		     POSITION_FIGHTING, LOKI, CLASS_ALL, 1, 15, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SHOCKING_GRASP, 1, 0, "shocking grasp", cast_shocking_grasp, 12, 15,
		     50, TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 1, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SLEEP, 1, 0, "sleep", cast_sleep, 24, 15, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_STANDING, LOKI, CLASS_ALL, 3,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_STONE_SKIN, 1, 0, "stoneskin", cast_stone_skin, 24, 20, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, 16, 32, LOKI, LOKI, 14,
		     LOKI);
	ASSIGN_SPELL(SPELL_STRENGTH, 1, 0, "strength", cast_strength, 12, 10, 50, TAR_CHAR_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, 4, LOW_IMMORTAL, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_SUCCOR, 1, 0, "succor", cast_succor, 24, 15, 50, TAR_IGNORE,
		     POSITION_STANDING, LOKI, CLASS_ALL, 21, 18, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_SUMMON, 1, 0, "summon", cast_summon, 36, 20, 50, TAR_CHAR_WORLD,
		     POSITION_STANDING, LOKI, CLASS_ALL, 18, 16, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_TELEPORT, 1, 0, "teleport", cast_teleport, 12, 33, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT, POSITION_FIGHTING, LOKI, CLASS_ALL, 8,
		     LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_TRUE_SIGHT, 1, 0, "true sight", cast_true_seeing, 24, 20, 50,
		     TAR_CHAR_ROOM, POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 12, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_TURN, 1, 0, "turn", cast_turn, 12, 5, 50, TAR_CHAR_ROOM,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOW_IMMORTAL, 1, LOKI, LOKI, LOKI,
		     LOKI);
	ASSIGN_SPELL(SPELL_VENTRILOQUATE, 1, 0, "ventriloquate", cast_ventriloquate, 12, 5, 50,
		     TAR_CHAR_ROOM | TAR_OBJ_ROOM | TAR_SELF_NONO, POSITION_STANDING, LOKI,
		     CLASS_ALL, 1, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_VISIONS, 1, 0, "visions", cast_visions, 12, 25, 40, TAR_CHAR_WORLD,
		     POSITION_STANDING, LOKI, CLASS_ALL, LOKI, 15, LOKI, LOKI, 30, LOKI);
	ASSIGN_SPELL(SPELL_WATER_BREATH, 1, 0, "water breath", cast_water_breath, 12, 15, 50,
		     TAR_CHAR_ROOM, POSITION_FIGHTING, LOKI, CLASS_ALL, 4, LOW_IMMORTAL, LOKI,
		     LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_WEAKNESS, 1, 0, "weakness", cast_weakness, 12, 10, 50,
		     TAR_CHAR_ROOM | TAR_FIGHT_VICT | TAR_VIOLENT, POSITION_FIGHTING, LOKI,
		     CLASS_ALL, 4, LOW_IMMORTAL, LOKI, LOKI, LOKI, LOKI);
	ASSIGN_SPELL(SPELL_WORD_OF_RECALL, 1, 0, "word of recall", cast_word_of_recall, 12, 5,
		     50, TAR_CHAR_ROOM | TAR_SELF_ONLY, POSITION_FIGHTING, LOKI, CLASS_ALL,
		     LOW_IMMORTAL, 10, LOKI, LOKI, LOKI, LOKI);

	for (i = 0; i < MAX_SKILLS; i++)
	    if (!spell[i])
		spell[i] = my_strdup("unknown");
    }
    return spell[Spell];
}

char                                   *damage_name(int Type)
{
    if (Type < TYPE_HIT)
	switch (Type) {
	    case 0:
		Type = TYPE_SMITE;
		break;
	    case 1:
		Type = TYPE_STAB;
		break;
	    case 2:
		Type = TYPE_WHIP;
		break;
	    case 3:
		Type = TYPE_SLASH;
		break;
	    case 4:
		Type = TYPE_SMASH;
		break;
	    case 5:
		Type = TYPE_CLEAVE;
		break;
	    case 6:
		Type = TYPE_CRUSH;
		break;
	    case 7:
		Type = TYPE_BLUDGEON;
		break;
	    case 8:
		Type = TYPE_CLAW;
		break;
	    case 9:
		Type = TYPE_BITE;
		break;
	    case 10:
		Type = TYPE_STING;
		break;
	    case 11:
		Type = TYPE_PIERCE;
		break;
	    default:
		Type = TYPE_HIT;
		break;
	}
    Type -= TYPE_HIT;
    switch (Type) {
	case 0:
	    return "Hit";
	case 1:
	    return "Bludgeon";
	case 2:
	    return "Piercing";
	case 3:
	    return "Slashing";
	case 4:
	    return "Whip";
	case 5:
	    return "Claw";
	case 6:
	    return "Bite";
	case 7:
	    return "Stinging";
	case 8:
	    return "Crushing";
	case 9:
	    return "Cleaving";
	case 10:
	    return "Stabbing";
	case 11:
	    return "Smashing";
	case 12:
	    return "Smiting";
	default:
	    return "unknown";
    }
}

int remap_mob_vnum(mobs *Mobs, int VNum)
{
    register int                            i;

    for (i = 0; i < Mobs->Count; i++)
	if (Mobs->Mob[i].Number == VNum)
	    return i;
    return -1;
}

char                                   *mob_name(mobs *Mobs, int VNum)
{
    int                                     i;

    if ((i = remap_mob_vnum(Mobs, VNum)) != -1)
	return Mobs->Mob[i].ShortDesc;
    else
	return "a non-existant mob";
}

void check_duplicate_mobs(mobs *Mobs)
{
    register int                            i,
                                            tmp;

    if (!Quiet) {
	fprintf(stderr, "Checking for duplicate mob vnums...");
	fflush(stderr);
    }
    for (i = 0; i < Mobs->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	tmp = Mobs->Mob[i].Number;
	Mobs->Mob[i].Number = -1;
	if (remap_mob_vnum(Mobs, tmp) >= 0)
	    if (Debug)
		log_error("MOB [#%d] is DUPLICATED!!!", tmp);
	Mobs->Mob[i].Number = tmp;
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void set_mob_zones(zones *Zones, mobs *Mobs)
{
    register int                            i,
                                            j,
                                            CorrectZone;

    if (!Quiet) {
	fprintf(stderr, "Setting Zone id tags...");
	fflush(stderr);
    }
    for (i = 0; i < Mobs->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	CorrectZone = -1;
	for (j = 0; j < Zones->Count; j++)
	    if (Mobs->Mob[i].Number <= Zones->Zone[j].Top)
		if (Mobs->Mob[i].Number >= ((j > 0) ? Zones->Zone[j - 1].Top + 1 : 0)) {
		    CorrectZone = Zones->Zone[j].Number;
		    break;
		}
	if (CorrectZone == -1) {
	    if (Verbose)
		log_error("Holy BatTurds!  I have NO IDEA what zone this mob [#%d] "
			  "belongs to!\nPutting it in Zone %d...\n",
			  Mobs->Mob[i].Number, Zones->Zone[0].Number);
	    Mobs->Mob[i].Zone = Zones->Zone[0].Number;
	} else {
	    Mobs->Mob[i].Zone = CorrectZone;
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

void check_mob_zone_mismatch(zones *Zones, mobs *Mobs)
{
    register int                            i,
                                            CorrectZone;

    if (!Quiet) {
	fprintf(stderr, "Verifying proper Zone id tags...");
	fflush(stderr);
    }
    for (i = 0; i < Mobs->Count; i++) {
	if (!Quiet)
	    spin(stderr);
	CorrectZone = Mobs->Mob[i].Number / 100;
	if (Mobs->Mob[i].Zone != CorrectZone) {
	    log_error("Improper Zone ID of [#%d] for mob \"%s\" [#%d],\n"
		      "Should belong to Zone [#%d].\n",
		      Mobs->Mob[i].Zone, Mobs->Mob[i].Name, Mobs->Mob[i].Number, CorrectZone);
	    /*
	     * Mobs->Mob[i].Zone= CorrectZone; 
	     */
	}
    }
    if (!Quiet)
	fprintf(stderr, "done.\n");
}

/*
 * This routine loads the mob file from WileyMUD III format.
 */
mobs                                   *load_mobs(char *infile, zones *Zones)
{
    FILE                                   *ifp;
    vnum_index                             *MobIndex;
    mobs                                   *Mobs;
    char                                   *tmp;	       /* , tmp2[MAX_LINE_LEN], *tmp3; */
    char                                    tmpa[MAX_LINE_LEN],
                                            tmpb[MAX_LINE_LEN],
                                            tmpc[MAX_LINE_LEN],
                                            tmpd[MAX_LINE_LEN],
                                            tmpe[MAX_LINE_LEN],
                                            tmpf[MAX_LINE_LEN];
    register int                            i,
                                            j;
    int                                     ack;
    long                                    Line,
                                            Pos;

    if (!infile || !*infile)
	return NULL;
    if (!(MobIndex = make_index(infile, NULL)))
	return NULL;
    Mobs = (mobs *)get_mem(1, sizeof(mobs));
    bzero(Mobs, sizeof(mobs));
    Mobs->Count = MobIndex->Count;
    Mobs->Mob = (mob *)get_mem(Mobs->Count, sizeof(mob));
    bzero(Mobs->Mob, Mobs->Count * sizeof(mob));
    ifp = open_file(infile, "r");

    if (Verbose)
	fprintf(stderr, "Parsing Mob file...\n");
    else if (!Quiet) {
	fprintf(stderr, "Parsing Mob file...");
	fflush(stderr);
    }

    for (i = 0; i < Mobs->Count; i++) {
	Line = MobIndex->VNum[i].Line;
	Pos = MobIndex->VNum[i].Pos;
	Mobs->Mob[i].Number = MobIndex->VNum[i].Number;
	if (fseek(ifp, Pos, 0) < 0)
	    log_fatal("Cannot load Mob $%d from %s!", Mobs->Mob[i].Number, infile);
	if (!(tmp = get_line(ifp, &Line, &Pos, 1)))
	    log_fatal("Cannot get vnum for Mob #%d from %s!", Mobs->Mob[i].Number, infile);
	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Mobs->Mob[i].Name = my_strdup(tmp))))
	    log_fatal("Cannot get name for Mob #%d, %s at %d.",
		      Mobs->Mob[i].Number, infile, Line);

	if (Verbose)
	    fprintf(stderr, "  (%d) Parsing \"%s\"[#%d]...\n", i,
		    Mobs->Mob[i].Name, Mobs->Mob[i].Number);
	else if (!Quiet)
	    spin(stderr);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Mobs->Mob[i].ShortDesc = my_strdup(tmp))))
	    log_fatal("Cannot get short description for Mob #%d, %s at %d.",
		      Mobs->Mob[i].Number, infile, Line);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Mobs->Mob[i].LongDesc = my_strdup(tmp))))
	    log_fatal("Cannot get long description for Mob #%d, %s at %d.",
		      Mobs->Mob[i].Number, infile, Line);

	if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
	    (!(Mobs->Mob[i].Description = my_strdup(tmp))))
	    log_fatal("Cannot get description for Mob #%d, %s at %d.",
		      Mobs->Mob[i].Number, infile, Line);

	if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
	    ((ack = sscanf(tmp, " %d %d %d %c %d ", &(Mobs->Mob[i].ActFlags),
			   &(Mobs->Mob[i].AffectedBy), &(Mobs->Mob[i].Alignment),
			   &(Mobs->Mob[i].Type), &(Mobs->Mob[i].AttackCount))) < 4))
	    log_fatal("Cannot get main flags for Mob #%d, %s at %d.",
		      Mobs->Mob[i].Number, infile, Line);

	Mobs->Mob[i].ActFlags |= ACT_ISNPC;
	Mobs->Mob[i].Class = CLASS_WARRIOR;

	switch (Mobs->Mob[i].Type) {
	    case 'W':
	    case 'M':
	    case 'S':{
		    /*
		     * multi-attack value is grabbed by sscanf above, ack will equal 5 if present 
		     */
		    Mobs->Mob[i].Strength.Modifier = 14;
		    Mobs->Mob[i].Dexterity.Modifier = 14;
		    Mobs->Mob[i].Constitution.Modifier = 14;
		    Mobs->Mob[i].Intelligence.Modifier = 14;
		    Mobs->Mob[i].Wisdom.Modifier = 14;

		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %d %d %d %s %s ", &(Mobs->Mob[i].Level),
				&(Mobs->Mob[i].ToHit), &(Mobs->Mob[i].ArmourClass),
				tmpa, tmpb) != 5))
			log_fatal("Cannot get level flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    sscanf_dice(tmpa, &(Mobs->Mob[i].HitPoints.Rolls),
				&(Mobs->Mob[i].HitPoints.Die),
				&(Mobs->Mob[i].HitPoints.Modifier));
		    if (ack == 5) {			       /* an attack count was read in... must be > 0 */
			if (Mobs->Mob[i].AttackCount < 1)
			    Mobs->Mob[i].AttackCount = 1;
		    } else {
			Mobs->Mob[i].AttackCount = 1;
		    }
		    Mobs->Mob[i].Attack =
			(attack *)get_mem(Mobs->Mob[i].AttackCount, sizeof(attack));
		    bzero(Mobs->Mob[i].Attack, Mobs->Mob[i].AttackCount * sizeof(attack));

		    sscanf_dice(tmpb, &(Mobs->Mob[i].Attack[0].Rolls),
				&(Mobs->Mob[i].Attack[0].Die),
				&(Mobs->Mob[i].Attack[0].Modifier));
		    Mobs->Mob[i].Attack[0].Type = 0;
		    for (j = 1; j < Mobs->Mob[i].AttackCount; j++)
			Mobs->Mob[i].Attack[j] = Mobs->Mob[i].Attack[0];
		    Mobs->Mob[i].ManaPoints = 100;
		    Mobs->Mob[i].MovePoints = 100;

		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %d %d %d %d ", &(Mobs->Mob[i].Gold.Modifier),
				&(Mobs->Mob[i].Gold.Rolls), &(Mobs->Mob[i].Experience.Modifier),
				&(Mobs->Mob[i].Race)) < 2))
			log_fatal("Cannot get experience flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);

		    if (Mobs->Mob[i].Gold.Modifier < 0) {
			Mobs->Mob[i].Gold.Modifier = Mobs->Mob[i].Gold.Rolls;
			Mobs->Mob[i].Gold.Rolls = 0;
		    } else {
			Mobs->Mob[i].Experience.Modifier = Mobs->Mob[i].Gold.Rolls;
			Mobs->Mob[i].Gold.Rolls = 0;
			Mobs->Mob[i].Race = 0;
		    }

		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %d %d %d %d %d %d ", &(Mobs->Mob[i].Position),
				&(Mobs->Mob[i].DefaultPosition), &(Mobs->Mob[i].Sex),
				&(Mobs->Mob[i].Resistance), &(Mobs->Mob[i].Immunity),
				&(Mobs->Mob[i].Susceptible)) < 3))
			log_fatal("Cannot get position flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    if (Mobs->Mob[i].Sex < 3) {
			Mobs->Mob[i].Resistance =
			    Mobs->Mob[i].Immunity = Mobs->Mob[i].Susceptible = 0;
		    } else if (Mobs->Mob[i].Sex < 6) {
			Mobs->Mob[i].Sex -= 3;
		    } else {
			Mobs->Mob[i].Sex =
			    Mobs->Mob[i].Resistance =
			    Mobs->Mob[i].Immunity = Mobs->Mob[i].Susceptible = 0;
		    }

		    Mobs->Mob[i].Weight = 250;
		    Mobs->Mob[i].Height = 198;
		    for (j = 0; j < 5; j++)
			Mobs->Mob[i].SavingThrow[j] = max(20 - Mobs->Mob[i].Level, 2);

		    if (Mobs->Mob[i].Type == 'W') {
			if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
			    (!(Mobs->Mob[i].Sound = my_strdup(tmp))))
			    log_fatal("No local sound for Mob #%d, %s of %d.",
				      Mobs->Mob[i].Number, infile, Line);
			if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
			    (!(Mobs->Mob[i].DistantSound = my_strdup(tmp))))
			    log_fatal("No local sound for Mob #%d, %s of %d.",
				      Mobs->Mob[i].Number, infile, Line);
		    }
		}
		break;
	    case 'D':{
		    log_fatal("Type 'D' mob #%d, %s of %d are no longer supported.",
			      Mobs->Mob[i].Number, infile, Line);
		}
		break;
	    case 'C':{
		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %d %d %d %d %d %s ", &(Mobs->Mob[i].Race),
				&(Mobs->Mob[i].Class), &(Mobs->Mob[i].Sex),
				&(Mobs->Mob[i].Height), &(Mobs->Mob[i].Weight), tmpa) != 6))
			log_fatal("Cannot get race flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Gold.Rolls),
				&(Mobs->Mob[i].Gold.Die), &(Mobs->Mob[i].Gold.Modifier));
		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %s %d %s %d %d %d ", tmpa,
				&(Mobs->Mob[i].Level), tmpb,
				&(Mobs->Mob[i].ArmourClass), &(Mobs->Mob[i].ToHit),
				&(Mobs->Mob[i].AttackCount)) != 6))
			log_fatal("Cannot get experience flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Experience.Rolls),
				&(Mobs->Mob[i].Experience.Die),
				&(Mobs->Mob[i].Experience.Modifier));
		    sscanf_dice(tmpb, &(Mobs->Mob[i].HitPoints.Rolls),
				&(Mobs->Mob[i].HitPoints.Die),
				&(Mobs->Mob[i].HitPoints.Modifier));
		    Mobs->Mob[i].ManaPoints = 100;
		    Mobs->Mob[i].MovePoints = 100;
		    /*
		     * Mobs->Mob[i].ArmourClass *= 10; 
		     */
		    /*
		     * Mobs->Mob[i].ToHit = 20 - Mobs->Mob[i].ToHit; 
		     */
		    if (Mobs->Mob[i].AttackCount < 1)
			Mobs->Mob[i].AttackCount = 1;
		    Mobs->Mob[i].Attack =
			(attack *)get_mem(Mobs->Mob[i].AttackCount, sizeof(attack));
		    bzero(Mobs->Mob[i].Attack, Mobs->Mob[i].AttackCount * sizeof(attack));
		    for (j = 0; j < Mobs->Mob[i].AttackCount; j++) {
			if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			    (sscanf(tmp, " %s %d ", tmpa, &(Mobs->Mob[i].Attack[j].Type)) != 2))
			    log_fatal("Cannot get attack line %d for Mob #%d, %s at %d.",
				      j, Mobs->Mob[i].Number, infile, Line);
			sscanf_dice(tmpa, &(Mobs->Mob[i].Attack[j].Rolls),
				    &(Mobs->Mob[i].Attack[j].Die),
				    &(Mobs->Mob[i].Attack[j].Modifier));
		    }
		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %d %d %d ", &(Mobs->Mob[i].Immunity),
				&(Mobs->Mob[i].Resistance), &(Mobs->Mob[i].Susceptible)) != 3))
			log_fatal("Cannot get immunity flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %s %s %s %s %s %s ", tmpa, tmpb, tmpc, tmpd, tmpe, tmpf)
			 != 6))
			log_fatal("Cannot get stat flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Strength.Rolls),
				&(Mobs->Mob[i].Strength.Die),
				&(Mobs->Mob[i].Strength.Modifier));
		    sscanf_dice(tmpa, &(Mobs->Mob[i].ExtraStrength.Rolls),
				&(Mobs->Mob[i].ExtraStrength.Die),
				&(Mobs->Mob[i].ExtraStrength.Modifier));
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Dexterity.Rolls),
				&(Mobs->Mob[i].Dexterity.Die),
				&(Mobs->Mob[i].Dexterity.Modifier));
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Constitution.Rolls),
				&(Mobs->Mob[i].Constitution.Die),
				&(Mobs->Mob[i].Constitution.Modifier));
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Intelligence.Rolls),
				&(Mobs->Mob[i].Intelligence.Die),
				&(Mobs->Mob[i].Intelligence.Modifier));
		    sscanf_dice(tmpa, &(Mobs->Mob[i].Wisdom.Rolls), &(Mobs->Mob[i].Wisdom.Die),
				&(Mobs->Mob[i].Wisdom.Modifier));
		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1)))
			||
			(sscanf
			 (tmp, " %d %d %d %d %d ", &(Mobs->Mob[i].SavingThrow[0]),
			  &(Mobs->Mob[i].SavingThrow[1]), &(Mobs->Mob[i].SavingThrow[2]),
			  &(Mobs->Mob[i].SavingThrow[3]), &(Mobs->Mob[i].SavingThrow[4])) != 5))
			log_fatal("Cannot get saving throws for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);
		    for (j = 0; j < 5; j++)
			if (!Mobs->Mob[i].SavingThrow[j])
			    Mobs->Mob[i].SavingThrow[j] = max(20 - Mobs->Mob[i].Level, 2);
		    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
			(sscanf(tmp, " %d %d %d %d ", &(Mobs->Mob[i].Position),
				&(Mobs->Mob[i].DefaultPosition), &ack,
				&(Mobs->Mob[i].SkillCount)) < 2))
			log_fatal("Cannot get position flags for Mob #%d, %s at %d.",
				  Mobs->Mob[i].Number, infile, Line);

		    if (ack) {
			if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
			    (!(Mobs->Mob[i].Sound = my_strdup(tmp))))
			    log_fatal("No local sound for Mob #%d, %s of %d.",
				      Mobs->Mob[i].Number, infile, Line);
			if ((!(tmp = get_tilde_string(ifp, &Line, &Pos))) ||
			    (!(Mobs->Mob[i].DistantSound = my_strdup(tmp))))
			    log_fatal("No local sound for Mob #%d, %s of %d.",
				      Mobs->Mob[i].Number, infile, Line);
		    }
		    if (Mobs->Mob[i].SkillCount) {
			Mobs->Mob[i].Skill =
			    (skill *)get_mem(Mobs->Mob[i].SkillCount, sizeof(skill));
			bzero(Mobs->Mob[i].Skill, Mobs->Mob[i].SkillCount * sizeof(skill));
			for (j = 0; j < Mobs->Mob[i].SkillCount; j++) {
			    if ((!(tmp = get_line(ifp, &Line, &Pos, 1))) ||
				(sscanf(tmp, " %d %d %d ", &(Mobs->Mob[i].Skill[j].Number),
					&(Mobs->Mob[i].Skill[j].Learned),
					&(Mobs->Mob[i].Skill[j].Recognise)) != 3))
				log_fatal("Cannot get skill line %d for Mob #%d, %s at %d.", j,
					  Mobs->Mob[i].Number, infile, Line);
			}
		    }
		}
		break;
	    default:
		log_fatal("I have NO clue what kind of mob #%d, %s of %d is.",
			  Mobs->Mob[i].Number, infile, Line);
		break;
	}
    }
    if (Verbose)
	fprintf(stderr, "Parsed %d mobs in World.\n", Mobs->Count);
    else if (!Quiet) {
	fprintf(stderr, "done.\n");
    }
    fclose(ifp);
    check_duplicate_mobs(Mobs);
    set_mob_zones(Zones, Mobs);
    check_mob_zone_mismatch(Zones, Mobs);
    return Mobs;
}