#include "LevelManager.h"
#include "WorldManager.h"
#include "GameManager.h"
#include "Powerups.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

Boolean ReadLn(short Ref, char * TheData)
{
	int i = 0;
	long DataSize;
	OSErr Err = noErr;
	
	do
	{
		DataSize = 1;
		FSRead(Ref, &DataSize, &TheData[i]);
		i++;
	} while(TheData[i-1] != 0x0A && TheData[i-1] != 0x0D && !Err && DataSize);
	
	TheData[i] = '\0';
	if(Err || !DataSize) return false;
	return true;
}

void DrawLevel(VLevel * l)
{
	int theRoomX;
	int theRoomY;
	int theRoomZ;
	int theWall;
	
	glEnable(GL_CULL_FACE);
	for (theRoomX = 0; theRoomX < l->SizeX; theRoomX++) {
		for (theRoomY = 0; theRoomY < l->SizeY; theRoomY++) {
			for (theRoomZ = 0; theRoomZ < l->SizeZ; theRoomZ++) {
				for(theWall = 0; theWall < 4; theWall++)
					if(l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[theWall])
						DrawObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[theWall]);
				DrawObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground);
				DrawObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling);
			}
		}
	}
	glDisable(GL_CULL_FACE);
}

void CleanUpLevel(VLevel * l)
{
	int theRoomX;
	int theRoomY;
	int theRoomZ;
	int theWall;
	VObjectWrapper * theWObject;
	
	for (theRoomX = 0; theRoomX < l->SizeX; theRoomX++) {
		for (theRoomY = 0; theRoomY < l->SizeY; theRoomY++) {
			for (theRoomZ = 0; theRoomZ < l->SizeZ; theRoomZ++) {
				for(theWall = 0; theWall < 4; theWall++)
					CleanUpObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[theWall]);
				CleanUpObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground);
				CleanUpObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling);
			}
		}
	}
	if (l->Rooms != NULL) {
		DisposePtr((Ptr) l->Rooms);
		l->Rooms = NULL;
	}
	if (l->Cells != NULL) {
		DisposePtr((Ptr) l->Cells);
		l->Cells = NULL;
	}
	
	while(l->Objects != NULL)
	{
		theWObject = l->Objects;
		l->Objects = theWObject->next;
		CleanUpWObject(theWObject);
		DisposePtr((Ptr) theWObject);
	}
}

static void CreateRooms(VLevel * l)
{
	int theRoomX, theRoomY, theRoomZ;
	int theWall;
	
	for (theRoomX = 0; theRoomX < l->SizeX; theRoomX++) {
		for (theRoomY = 0; theRoomY < l->SizeY; theRoomY++) {
			for (theRoomZ = 0; theRoomZ < l->SizeZ; theRoomZ++) {
				for(theWall = 0; theWall < 4; theWall++)
				{
					InitObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[theWall]);
					l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[theWall].Position.x = 40*theRoomX;
					l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[theWall].Position.y = 40*theRoomY;
					l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[theWall].Position.z = 40*theRoomZ;
					l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[theWall] = false;
				}
				
				InitObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground);
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground.Position.x = 40*theRoomX;
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground.Position.y = 40*theRoomY;
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground.Position.z = 40*theRoomZ;
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[4] = false;
				
				InitObject(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling);
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling.Position.x = 40*theRoomX;
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling.Position.y = 40*theRoomY;
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling.Position.z = 40*theRoomZ;
				l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[5] = false;
				
				if(l->Cells[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX])
				{
					if(theRoomX > 0)
					{
						if(!l->Cells[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + (theRoomX - 1)])
						{
							BuildLeftWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[0].Model);
							l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[0] = true;
						}
					} else
					{
						BuildLeftWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[0].Model);
						l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[0] = true;
					}
					if(theRoomX < (l->SizeX - 1))
					{
						if(!l->Cells[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + (theRoomX + 1)])
						{
							BuildRightWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[1].Model);
							l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[1] = true;
						}
					} else
					{
						BuildRightWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[1].Model);
						l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[1] = true;
					}
					if(theRoomZ > 0)
					{
						if(!l->Cells[(theRoomY * (l->SizeX * l->SizeZ)) + ((theRoomZ - 1) * l->SizeX) + theRoomX])
						{
							BuildFrontWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[2].Model);
							l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[2] = true;
						}
					} else
					{
						BuildFrontWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[2].Model);
						l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[2] = true;
					}
					if(theRoomZ < (l->SizeZ - 1))
					{
						if(!l->Cells[(theRoomY * (l->SizeX * l->SizeZ)) + ((theRoomZ + 1) * l->SizeX) + theRoomX])
						{
							BuildBackWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[3].Model);
							l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[3] = true;
						}
					} else
					{
						BuildBackWallModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Walls[3].Model);
						l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[3] = true;
					}
					if(theRoomY > 0)
					{
						if(!l->Cells[((theRoomY - 1) * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX])
						{
							BuildFloorModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground.Model);
							l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[4] = true;
						}
					} else
					{
						BuildFloorModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ground.Model);
						l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[4] = true;
					}
					if(theRoomY < (l->SizeY - 1))
					{
						if(!l->Cells[((theRoomY + 1) * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX])
						{
							BuildCeilingModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling.Model);
							l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[5] = true;
						}
					} else
					{
						BuildCeilingModel(&l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].Ceiling.Model);
						l->Rooms[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX].IsWall[5] = true;
					}
				}
			}
		}
	}
}

Boolean LoadLevel(VLevel * l, char * name, void * world)
{
	OSErr error;
	int numMatches;
	FSRef FileRef;
	CFURLRef URL;
	CFBundleRef Bundle;
	CFStringRef String;
	
	FSSpec Spec;
	short Ref;
	
	int theRoomX, theRoomY, theRoomZ;
	long DataSize;
	char TheData[1024];
	
	char SymbolName[1024];
	Boolean added;
	VObjectWrapper * o;
	VEnemy * e;
	VWorld * w;
	VObject * ob;
	
	w = (VWorld *) world;
	TheData[1] = '\0';
	
	l->Objects = NULL;
	
	String = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
	Bundle = CFBundleGetMainBundle();
	URL = CFBundleCopyResourceURL(Bundle, String, NULL, NULL);
	if(URL)
	{
		CFURLGetFSRef(URL, &FileRef);
		error = FSGetCatalogInfo(&FileRef, kFSCatInfoNone, NULL, NULL, &Spec, NULL);
		
		CFRelease((CFTypeRef)URL);
	}
	CFRelease((CFTypeRef)String);
	if (error != noErr) return 0;
	
	error = FSpOpenDF(&Spec, fsRdPerm, &Ref);
	if (error != noErr) return 0;
	if (!ReadLn(Ref, TheData)) return 0;
	numMatches = sscanf(TheData, "LevelSize: %d, %d, %d", &l->SizeX, &l->SizeY, &l->SizeZ);
	if (numMatches < 3) return 0;
	l->Rooms = (VRoom *) NewPtr(sizeof(VRoom) * l->SizeX * l->SizeY * l->SizeZ);
	l->Cells = (short *) NewPtr(sizeof(short) * l->SizeX * l->SizeY * l->SizeZ);
	for (theRoomY = 0; theRoomY < l->SizeY; theRoomY++) {
		for (theRoomZ = 0; theRoomZ < l->SizeZ; theRoomZ++) {
			for (theRoomX = 0; theRoomX < l->SizeX; theRoomX++) {
				DataSize = 1;
				FSRead(Ref, &DataSize, &TheData[0]);
				while (TheData[0] == 0x0A || TheData[0] == 0x0D)
				{
					DataSize = 1;
					FSRead(Ref, &DataSize, &TheData[0]);
				}
				numMatches = sscanf(TheData, "%hd", &l->Cells[(theRoomY * (l->SizeX * l->SizeZ)) + (theRoomZ * l->SizeX) + theRoomX]);
				if (numMatches < 1) {
					DisposePtr((Ptr) l->Rooms);
					l->Rooms = NULL;
					DisposePtr((Ptr) l->Cells);
					l->Cells = NULL;
					return 0;
				}
			}
		}
	}
	
	CreateRooms(l);
	
	while(ReadLn(Ref, TheData))
	{
		added = false;
		if (!memcmp(TheData, "StartPos", 8))
			sscanf(TheData, "StartPos: %f, %f, %f", &l->StartPos.x, &l->StartPos.y, &l->StartPos.z);
		else if (!memcmp(TheData, "Look", 4)) {
			sscanf(TheData, "Look: %s", SymbolName);
			if (!strcmp(SymbolName, "Left"))
				l->Look = LEFT;
			else if (!strcmp(SymbolName, "Right"))
				l->Look = RIGHT;
			else if (!memcmp(SymbolName, "Forward", 7))
				l->Look = FORWARDS;
			else if (!memcmp(SymbolName, "Backward", 8))
				l->Look = BACKWARDS;
		}
		
		if (!strcmp(TheData, "Enemy\x0A") || !strcmp(TheData, "Enemy\x0D"))
		{
			added = true;
			e = (VEnemy *)NewPtrClear(sizeof(VEnemy));
			InitEnemy(e, w);
			AllocateWObject(&o);
			o->e = e;
			o->Type = VENEMY;
			o->next = l->Objects;
			do
			{
				if (!ReadLn(Ref, TheData)) break;
				if(!memcmp(TheData, "PosX", 4))
					sscanf(TheData, "PosX: %f", &e->Object.Position.x);
				else if(!memcmp(TheData, "PosY", 4))
					sscanf(TheData, "PosY: %f", &e->Object.Position.y);
				else if(!memcmp(TheData, "PosZ", 4))
					sscanf(TheData, "PosZ: %f", &e->Object.Position.z);
				else if(!memcmp(TheData, "Shields", 7))
					sscanf(TheData, "Shields: %d", &e->Shields);
				else if(!memcmp(TheData, "BonusNum", 8))
					sscanf(TheData, "BonusNum: %d", &e->Object.PowerupAmount);
				else if(!memcmp(TheData, "Destroy", 7))
					sscanf(TheData, "Destroy: %hd", &e->Object.MustBeDestroyed);
				else if(!memcmp(TheData, "Bonus", 5)) {
					sscanf(TheData, "Bonus: %s", SymbolName);
					if (!strcmp(SymbolName, "Health"))
						e->Object.PowerupType = POWERUPTYPEHEALTH;
					else if (!strcmp(SymbolName, "Rockets"))
						e->Object.PowerupType = POWERUPTYPEROCKETS;
					else if (!strcmp(SymbolName, "Turbo"))
						e->Object.PowerupType = POWERUPTYPETURBO;
					else if (!strcmp(SymbolName, "MachineGun"))
						e->Object.PowerupType = POWERUPTYPEMACHINEGUN;
					else if (!strcmp(SymbolName, "SpreadGun"))
						e->Object.PowerupType = POWERUPTYPESPREADGUN;
					else if (!strcmp(SymbolName, "LongShotGun"))
						e->Object.PowerupType = POWERUPTYPELONGSHOTGUN;
				}
				else if(!memcmp(TheData, "AIType", 6)) {
					sscanf(TheData, "AIType: %s", SymbolName);
					if (!strcmp(SymbolName, "DumbShooter"))
						SetEnemyAI(e, DumbShooterAI);
					else if (!strcmp(SymbolName, "SmartShooter"))
						SetEnemyAI(e, SmartShooterAI);
					else if (!strcmp(SymbolName, "Kamikaze"))
						SetEnemyAI(e, KamikazeAI);
					else if (!strcmp(SymbolName, "Stationary"))
						SetEnemyAI(e, StationaryAI);
				}
				else if(!memcmp(TheData, "Facing", 6)) {
					sscanf(TheData, "Bonus: %s", SymbolName);
					if (!strcmp(SymbolName, "Forward")) {
						e->Object.Front.x = 0.0;
						e->Object.Front.y = 0.0;
						e->Object.Front.z = -1.0;
						e->Object.Up.x = 0.0;
						e->Object.Up.y = 1.0;
						e->Object.Up.z = 0.0;
						e->Object.Right.x = 1.0;
						e->Object.Right.y = 0.0;
						e->Object.Right.z = 0.0;
					} else if (!strcmp(SymbolName, "Backward")) {
						e->Object.Front.x = 0.0;
						e->Object.Front.y = 0.0;
						e->Object.Front.z = 1.0;
						e->Object.Up.x = 0.0;
						e->Object.Up.y = 1.0;
						e->Object.Up.z = 0.0;
						e->Object.Right.x = -1.0;
						e->Object.Right.y = 0.0;
						e->Object.Right.z = 0.0;
					} else if (!strcmp(SymbolName, "Left")) {
						e->Object.Front.x = -1.0;
						e->Object.Front.y = 0.0;
						e->Object.Front.z = 0.0;
						e->Object.Up.x = 0.0;
						e->Object.Up.y = 1.0;
						e->Object.Up.z = 0.0;
						e->Object.Right.x = 0.0;
						e->Object.Right.y = 0.0;
						e->Object.Right.z = -1.0;
					} else if (!strcmp(SymbolName, "Right")) {
						e->Object.Front.x = 1.0;
						e->Object.Front.y = 0.0;
						e->Object.Front.z = 0.0;
						e->Object.Up.x = 0.0;
						e->Object.Up.y = 1.0;
						e->Object.Up.z = 0.0;
						e->Object.Right.x = 0.0;
						e->Object.Right.y = 0.0;
						e->Object.Right.z = 1.0;
					} else if (!strcmp(SymbolName, "Up")) {
						e->Object.Front.x = 0.0;
						e->Object.Front.y = 1.0;
						e->Object.Front.z = 0.0;
						e->Object.Up.x = 0.0;
						e->Object.Up.y = 0.0;
						e->Object.Up.z = 1.0;
						e->Object.Right.x = 0.0;
						e->Object.Right.y = 0.0;
						e->Object.Right.z = 1.0;
					} else if (!strcmp(SymbolName, "Down")) {
						e->Object.Front.x = 0.0;
						e->Object.Front.y = -1.0;
						e->Object.Front.z = 0.0;
						e->Object.Up.x = 0.0;
						e->Object.Up.y = 0.0;
						e->Object.Up.z = 1.0;
						e->Object.Right.x = 0.0;
						e->Object.Right.y = 0.0;
						e->Object.Right.z = -1.0;
					}
				}
			} while(strcmp(TheData, "End\x0A") && strcmp(TheData, "End\x0D"));
		}
		if(added)
		{
			if(l->Objects)
			{
				l->Objects->previous = o;
			}
			l->Objects = o;
		}
		
		added = false;
		if(!strcmp(TheData, "Object\x0A") || !strcmp(TheData, "Object\x0D"))
		{
			added = true;
			ob = (VObject *)NewPtrClear(sizeof(VObject));
			InitObject(ob);
			AllocateWObject(&o);
			o->o = ob;
			o->Type = VOBJECT;
			o->next = l->Objects;
			do
			{
				if (!ReadLn(Ref, TheData)) return 0;
				if(!memcmp(TheData, "PosX", 4))
					sscanf(TheData, "PosX: %f", &ob->Position.x);
				else if(!memcmp(TheData, "PosY", 4))
					sscanf(TheData, "PosY: %f", &ob->Position.y);
				else if(!memcmp(TheData, "PosZ", 4))
					sscanf(TheData, "PosZ: %f", &ob->Position.z);
				else if(!memcmp(TheData, "Shields", 7))
					sscanf(TheData, "Shields: %d", &ob->Durability);
				else if(!memcmp(TheData, "BonusNum", 8))
					sscanf(TheData, "BonusNum: %d", &ob->PowerupAmount);
				else if(!memcmp(TheData, "Destroy", 7))
					sscanf(TheData, "Destroy: %hd", &ob->MustBeDestroyed);
				else if(!memcmp(TheData, "Bonus", 5)) {
					sscanf(TheData, "Bonus: %s", SymbolName);
					if (!strcmp(SymbolName, "Health"))
						ob->PowerupType = POWERUPTYPEHEALTH;
					else if (!strcmp(SymbolName, "Rockets"))
						ob->PowerupType = POWERUPTYPEROCKETS;
					else if (!strcmp(SymbolName, "Turbo"))
						ob->PowerupType = POWERUPTYPETURBO;
					else if (!strcmp(SymbolName, "MachineGun"))
						ob->PowerupType = POWERUPTYPEMACHINEGUN;
					else if (!strcmp(SymbolName, "SpreadGun"))
						ob->PowerupType = POWERUPTYPESPREADGUN;
					else if (!strcmp(SymbolName, "LongShotGun"))
						ob->PowerupType = POWERUPTYPELONGSHOTGUN;
				}
				else if(!memcmp(TheData, "Type:", 5))
				{
					sscanf(TheData, "Type: %s", SymbolName);
					if(!strcmp(SymbolName, "Target"))
						BuildTargetModel(&ob->Model);
				}
			} while(strcmp(TheData, "End\x0A") && strcmp(TheData, "End\x0D"));
			
			CalculateRadius(ob);
		}
		if(added)
		{
			if(l->Objects)
			{
				l->Objects->previous = o;
			}
			l->Objects = o;
		}
	}
	
	FSClose(Ref);
	return 1;
}

void BuildEmptyLevel(VLevel * l) {
  l->SizeX = l->SizeY = l->SizeZ = 1;
  l->StartPos.x = 20.0;
  l->StartPos.y = 20.0;
  l->StartPos.z = 20.0;
  l->Look = FORWARDS;
  l->Rooms = (VRoom *) NewPtr(sizeof(VRoom));
  l->Cells = (short *) NewPtr(sizeof(short));
  *l->Cells = 1;
  CreateRooms(l);
  l->Objects = NULL;
}

void CopyLevel(VLevel * src, VLevel * dest) {
	VObjectWrapper * srcObjectList, ** destObjectList, * previous;
	
	dest->SizeX = src->SizeX;
	dest->SizeY = src->SizeY;
	dest->SizeZ = src->SizeZ;
	dest->StartPos = src->StartPos;
	dest->Look = src->Look;
	dest->Rooms = (VRoom *) NewPtr(sizeof(VRoom) * (dest->SizeX * dest->SizeY * dest->SizeZ));
	BlockMove(src->Rooms, dest->Rooms, (sizeof(VRoom) * (dest->SizeX * dest->SizeY * dest->SizeZ)));
	dest->Cells = (short *) NewPtr(sizeof(short) * (dest->SizeX * dest->SizeY * dest->SizeZ));
	BlockMove(src->Cells, dest->Cells, (sizeof(short) * (dest->SizeX * dest->SizeY * dest->SizeZ)));
	if (src->Objects == NULL) dest->Objects = NULL;
	else {
		destObjectList = &dest->Objects;
		previous = NULL;
		for (srcObjectList = src->Objects; srcObjectList != NULL; srcObjectList = srcObjectList->next) {
		  CopyWObject(srcObjectList, destObjectList);
		  (**destObjectList).previous = previous;
		  if (previous != NULL) previous->next = *destObjectList;
		  previous = *destObjectList;
		  destObjectList = &(**destObjectList).next;
		}
	}
}

void BuildBossArena(VLevel * l, int Length, int Height, int Width)
{
	int x, y, z;
  l->SizeX = Length;
  l->SizeY = Height;
  l->SizeZ = Width;
  l->StartPos.x = 20.0;
  l->StartPos.y = 20.0;
  l->StartPos.z = 20.0;
  l->Look = FORWARDS;
  l->Rooms = (VRoom *) NewPtr(sizeof(VRoom) * Length * Height * Width);
  l->Cells = (short *) NewPtr(sizeof(short) * Length * Height * Width);
  for(x = 0; x < Length; x++)
  	for(y = 0; y < Height; y++)
  		for(z = 0; z < Width; z++)
  			l->Cells[(y * (l->SizeX * l->SizeZ)) + (z * l->SizeX) + x] = 1;
  CreateRooms(l);
  l->Objects = NULL;
}
