#import "BWGameData.h"
#import "BWMainObject.h"

@implementation BWGameData

# pragma mark -

- (void)awakeFromNib
{
	textStrings = [[NSMutableArray alloc] initWithCapacity:5];
	tiles = [[NSMutableArray alloc] initWithCapacity:0x100];
	tilesEnemies = [[NSMutableArray alloc] initWithCapacity:8];	// Array of arrays
	tilesBosses = [[NSMutableArray alloc] initWithCapacity:9];
	
	displayHex = NO;
	boxPaletteBasePosition = [boxPalette frame];
	
	//[tableExperience setDelegate:self];
	//[tableDamage setDelegate:self];
	rom = nil;
}

- (void)open:(NSMutableData *)theRom
{
	rom = theRom;
	
	[textStrings removeAllObjects];
	
	int i,j;
	
	for (i=0; i<64; i++) {
		[[matrixMagic cellAtRow:(i / 8) column:(i % 8)] setTag:i];
	}
	
	for (i=0; i<24; i++) {
		[[matrixLevels cellAtRow:(i / 8) column:(i % 8)] setTag:i];
	}
	
	for (i=0; i<10; i++) {
		for (j=0; j<14; j++) {
			[[matrixText cellAtRow:i column:j] setBordered:NO];
		}
	}
	
	[self loadAttack];
	[self loadMagic];
	[self setLevels]; [self setLevelsNames];
	//[self setTextStrings];
	[self setBeginning];
	[self setMisc];
	
	[self loadEnemyAttributes];
	[self loadExperience];
	[self loadDamage];
	[self loadTiles];
	[self loadTilesEnemies];
	[self loadTilesBosses];
	
	[self changeWorld:menuWorld];
}

- (void)save
{
	[self saveAttack];
	[self saveMagic];
	[self saveLevels];
	[self saveText];
	[self saveEnemies];
	[self saveBeginning];
	[self saveMisc];
}

# pragma mark -

- (void)loadTiles
{
	int i,x;
	unsigned int offset;
	struct sCol tp[4];
	
	[tiles removeAllObjects];
	
	[objMain setScale:2];
	
	unsigned char palCode = 4;
	ptr = [rom bytes] + 0xC00E + (palCode * 0x10) + 0x10;
	for (x=0; x<4; x++) {
		tp[x] = nesPal[*ptr++];
	}
	tp[0] = nesPal[0x0F];	// For black background
	
	offset = 0x20000 + 0x6000 + 0x1000 + 0x10;
	for (i=0; i<0x100; i++) {
		[tiles addObject:[objMain tileWithOffset:offset palette:tp]];
		offset += 0x10;
	}
}

- (void)loadTilesEnemies
{
	[tilesEnemies removeAllObjects];
	
	[objMain setScale:1];
	
	NSMutableArray *tlist = [NSMutableArray arrayWithCapacity:16];
	NSImage *spriteImage;
	NSMutableArray *tilesEnemiesArray;
	
	int i,j,k,x;
	int offset;
	unsigned char spriteSize;
	unsigned char palCode;
	struct sCol tp[4];
	
	unsigned bank;
	unsigned char banks[6] = { 0 , 1 , 2 , 3 , 3 , 4 };
	unsigned char graphicsBanks[6] = { 1 , 2 , 3 , 4 , 9 , 6 };
	//unsigned char tileMappingsBank;
	
	for (i=0; i<6; i++) {
		
		tilesEnemiesArray = [NSMutableArray array];
		
		bank = banks[i];
		
		// banks[i];
		// graphicsBanks[i];
		
		//tileMappingsBank = bank;
		//if (i == 4) tileMappingsBank = 4;
		//if (i == 5) tileMappingsBank = 5;
		
		for (j=0; j<0x24; j++) {
			
			if (i < 2 && j == 0x0B) { [tilesEnemiesArray addObject:[NSImage imageNamed:@"BubbleGenerator.png"]]; continue; }
			if (i < 2 && j == 0x0C) { [tilesEnemiesArray addObject:[NSImage imageNamed:@"RockGenerator.png"]]; continue; }
			if (i == 2 && (j == 0x0C || j == 0x21 || j == 0x22)) { [tilesEnemiesArray addObject:[NSImage imageNamed:@"Dialog.png"]]; continue; }
			if (i == 2 && j == 0x23) { [tilesEnemiesArray addObject:[NSImage imageNamed:@"TownfolksGenerator.png"]]; continue; }
			// Falling Blocks Generator
			// Tinsuit Generator
			// Crystal Slot
			// Energy Ball Shooter (Right/Left)
			
			[tlist removeAllObjects];
			
			palCode = ((enemyAttributes1[i][j]) & 0xC0) >> 6; //NSLog(@"%02X : %X",j,palCode);
			if (i == 2) palCode = (enemyAttributes2[i][j]) & 0x03;
			
			if (j <= 0x02) palCode = 1;						// Fairy, Red Jar, Locked Door (Enemy Attributes don't have the correct palette)
			if (j == 0x0F) palCode = 2;						// Bago Bago Generator (same palette as Bago)
			
			if (i == 2) {
				if (j == 0x03) palCode = 3;					// Ache
				if (j == 0x04) palCode = 3;					// Bot
				if (j == 0x05) palCode = 2;					// Bit
				if (j == 0x07) palCode = 2;					// Acheman
				if (j == 0x0A) palCode = 2;					// Ache (talker)
				if (j == 0x0B) palCode = 3;					// Bit (talker)
				if (j == 0x0F) palCode = 1;					// Wise Man
			}
			
			if (i < 2) {
				if (j == 0x1D) palCode = 1;					// Moby Generator (same palette as Moby)
				if (j == 0x21) palCode = 1;					// Dumb Moblin Generator (same palette as Dumb Moblin)
				if (j == 0x01) palCode = 2;					// Exception for Red Jar
				if (i == 1 && j == 0x1D) palCode = 2;		// Exception for Rock Tossing Lizalfos
			}
			
			if ((i == 3 || i == 4) && j == 0x06) palCode = 3;		// Slow Bubble (to differentiate from Fast Bubble)
			if ((i == 3 || i == 4) && j == 0x0B) palCode = 1;		// Tinsuit Generator (not necessary if arbitrary icon is used)
			if ((i == 3 || i == 4) && j == 0x14) palCode = 3;		// Crystal Slot (not necessary if arbitrary icon is used)
			if ((i == 3 || i == 4) && j == 0x15) palCode = 3;		// Crystal
			
			if (i == 4 && j == 0x0F) palCode = 3;			// Ra (instead of Bago Bago Generator)
			if (i == 4 && j == 0x10) palCode = 2;			// Flame (instead of Bago Bago)
			if (i == 4 && j == 0x1D) palCode = 2;			// Wizard (instead of Mago)
			if (i == 4 && j == 0x1E) palCode = 3;			// Doomknocker (instead of Guma)
			
			if (i == 5 && j == 0x15) palCode = 2;			// Fast Bubble (to differentiate from Slow Bubble)
			if (i == 5 && j == 0x17) palCode = 2;			// Exception for Big Bubble
			if (i == 5 && j == 0x20) palCode = 2;			// Electric Barrier (so it's not green)
			
			palCode *= 4;
			
			//palCode += 0x90;
			
			ptr = [rom bytes] + ((bank + 1) * 0x4000) + 0x0E + 0x90 + palCode + 0x10;
			//NSLog(@"%X",((bank + 1) * 0x4000) + 0x0E + 0x90 + palCode + 0x10);
			
			tp[0] = nesPal[0x40];
			//NSLog(@"%02X %02X %02X %02X",*ptr,*(ptr+1),*(ptr+2),*(ptr+3));
			for (x=1; x<4; x++) {
				tp[x] = nesPal[*(ptr + x)];
			}
			
			if (i != 2 && j == 0x13) {	// Elevator (except in Towns)
				for (k=0; k<18; k++) {
					if (k > 2 && k < 15) [tlist addObject:[objMain emptyTile]];
					else {
						offset = 0x20000 + (0x2000 * graphicsBanks[i]) + (0xAC * 0x10) + 0x10;
						[tlist addObject:[objMain tileWithOffset:offset palette:tp]];
					}
				}
				spriteImage = [objMain graphicWithTiles:tlist type:0x36];
				[tilesEnemiesArray addObject:spriteImage];
				continue;
			}
			
			spriteSize = tme[i][j][0];
			if (spriteSize == 0xFF) {
				[tilesEnemiesArray addObject:[NSImage imageNamed:@"Undefined.png"]];
				continue;
			}
			
			for (k=1; k<17; k++) {
				if (tme[i][j][k] == 0x00) break;
				if (tme[i][j][k] == 0x01) { [tlist addObject:[objMain emptyTile]]; continue; }
				
				offset = 0x20000 + (0x2000 * graphicsBanks[i]) + (tme[i][j][k] * 0x10) + 0x10;
				[tlist addObject:[objMain tileWithOffset:offset palette:tp]];
				
				if (i < 2 && j == 0x03 && k == 4) [objMain flipTile:[tlist lastObject] type:1];					// Myu
				if (i < 2 && j == 0x04 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];		// Bot
				
				if (i < 2 && j == 0x05 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];		// Bit
				if (i < 2 && j == 0x07 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];		// Ache
				if (i < 2 && j == 0x0A && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];		// Acheman
				
				if (i == 1 && j == 0x16 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];	// Leever
				
				if (i == 2) {	// Towns
					if ((j >= 0x03 && j <= 0x05) && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];
					if (j == 0x07 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];
					if ((j == 0x0A || j == 0x0B) && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];
				}
				
				if (bank == 3) {
					if (j == 0x03 && k == 4) [objMain flipTile:[tlist lastObject] type:1];						// Myu
					if (j == 0x04 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Bot
					if (j == 0x06 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Bubble - Slow (Palaces Type A/B)
					if (j == 0x0E && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Bubble - Fast (Palaces Type A/B)
				}
				
				if (bank == 4) {
					if (j == 0x03 && k == 4) [objMain flipTile:[tlist lastObject] type:1];						// Myu
					if (j == 0x04 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Bot
					if (j == 0x07 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Ache
					if (j == 0x0A && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Acheman
					if (j == 0x14 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Bubble - Slow (Great Palace)
					if (j == 0x15 && (k == 2 || k == 4)) [objMain flipTile:[tlist lastObject] type:1];			// Bubble - Fast (Great Palace)
					if (j == 0x17 && (((k - 1) % 4) > 1)) [objMain flipTile:[tlist lastObject] type:1];			// Big Bubble (Great Palace)
				}
			}
			
			spriteImage = [objMain graphicWithTiles:tlist type:spriteSize];
			
			// Add overlays to generator graphics (0F 1D 21)
			// And moving Octorok
			// Something for invisible enemies (needs Cross)
			
			[tilesEnemiesArray addObject:spriteImage];
		}
		
		//NSLog(@"%X",(char)[tilesEnemiesArray count]);
		
		[tilesEnemies addObject:tilesEnemiesArray];
		
	}
	
	/*NSString *path;
	 NSData *ddd;
	 for (i=0; i<[tilesEnemies count]; i++) {
		path = [[NSString stringWithFormat:@"~/Desktop/TestTiles/enemy%02d.tiff",i] stringByExpandingTildeInPath];
		ddd = [[tilesEnemies objectAtIndex:i] TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0];
		[ddd writeToFile:path atomically:YES];
	 }*/
}

/*- (NSImage *)tileWithOffset:(int)os palette:(struct sCol *)pal
{
	const char *p1;
	unsigned char *p2;
	
	p1 = [rom bytes] + os;
	
	int sr = 2;		// Scale Ratio
	int wh = sr * 8;
	
	NSImage *tileImage = [[NSImage alloc] initWithSize:NSMakeSize(wh,wh)];
	NSBitmapImageRep *tileRep = [[NSBitmapImageRep alloc] 
				initWithBitmapDataPlanes:NULL
							  pixelsWide:wh
							  pixelsHigh:wh
						   bitsPerSample:8
						 samplesPerPixel:4
								hasAlpha:YES
								isPlanar:NO
						  colorSpaceName:NSDeviceRGBColorSpace
							 bytesPerRow:(wh * 4)
							bitsPerPixel:32];
	
	p2 = [tileRep bitmapData];
	
	int i,j,k1,k2;
	unsigned char b1,b2,cp;
	
	for (i=0; i<8; i++) {
		
		b1 = *p1;
		b2 = *(p1 + 8);
		
		for (j=7; j>=0; j--) {
			
			cp = ((b1 >> j) & 0x01) + (((b2 >> j) & 0x01) * 2);
			
			for (k1=0; k1<sr*4; k1+=4) {
				for (k2=0; k2<sr*4; k2+=4) {
					
					if (pal[cp].r == 0xEF) {
						*( ( p2 + (wh * k1) ) + k2) = 0;
						*( ( p2 + (wh * k1) ) + k2 + 1) = 0;
						*( ( p2 + (wh * k1) ) + k2 + 2) = 0;
						*( ( p2 + (wh * k1) ) + k2 + 3) = 0;
					} else {
						*( ( p2 + (wh * k1) ) + k2) = pal[cp].r;
						*( ( p2 + (wh * k1) ) + k2 + 1) = pal[cp].g;
						*( ( p2 + (wh * k1) ) + k2 + 2) = pal[cp].b;
						*( ( p2 + (wh * k1) ) + k2 + 3) = 255;
					}
					
				}
			}
			
			p2 += (sr * 4);
			
		}
		
		p2 += sr * (sr - 1) * 8 * 4;
		p1++;
		
	}
	
	[tileImage addRepresentation:tileRep];
	return tileImage;
}*/

- (void)loadTilesBosses
{
	[tilesBosses removeAllObjects];
	
	NSMutableArray *tlist = [NSMutableArray arrayWithCapacity:24];
	NSImage *spriteImage;
	NSMutableArray *bossParts = [NSMutableArray arrayWithCapacity:10];
	
	int offset;
	unsigned char spriteSize;
	unsigned char palCode;
	struct sCol tp[4];
	
	unsigned char banks[10] = { 4 , 4 , 4 , 4 , 4 , 4 , 4 , 5 , 5 , 5 };
	unsigned char graphicsBanks[10] = { 4 , 5 , 9 , 9 , 0x0A , 0x0B , 0x0C , 0x0C , 6 , 6 };
	unsigned char palBosses[10] = { 2 , 3 , 3 , 3 , 2 , 2 , 1 , 1 , 3 , 3 };
	
	int i,j,x;
	for (i=0; i<10; i++) {
		
		[tlist removeAllObjects];
		
		palCode = palBosses[i] * 4;
		ptr = [rom bytes] + (banks[i] * 0x4000) + 0x0E + 0x90 + palCode + 0x10;
		
		tp[0] = nesPal[0x40];
		//NSLog(@"%02X %02X %02X %02X",*ptr,*(ptr+1),*(ptr+2),*(ptr+3));
		for (x=1; x<4; x++) {
			tp[x] = nesPal[*(ptr + x)];
		}
		
		spriteSize = tmboss[i][0];
		
		for (j=1; j<61; j++) {
			if (tmboss[i][j] == 0x00) break;
			if (tmboss[i][j] == 0x01) { [tlist addObject:[objMain emptyTile]]; continue; }
			
			offset = 0x20000 + (0x2000 * graphicsBanks[i]) + (tmboss[i][j] * 0x10) + 0x10;
			[tlist addObject:[objMain tileWithOffset:offset palette:tp]];
			
			if (i == 8 && ((j - 1) % 6) > 2) [objMain flipTile:[tlist lastObject] type:1];		// Giant Bot flipped tiles
			if (i == 9 && ((j - 1) % 6) > 2) [objMain flipTile:[tlist lastObject] type:1];		// Thunderbird flipped tiles
		}
		
		spriteImage = [objMain graphicWithTiles:tlist type:spriteSize];
		
		[bossParts addObject:spriteImage];
	}
	
	[tilesBosses addObject:[bossParts objectAtIndex:0]];	// Horsehead
	
	// Helmethead
	NSImage *helmethead = [[NSImage alloc] initWithSize:NSMakeSize(16,48)];
	[helmethead lockFocus];
	[[[tilesEnemies objectAtIndex:3] objectAtIndex:0x22] compositeToPoint:NSMakePoint(4,27) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:1] compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
	[helmethead unlockFocus];
	[tilesBosses addObject:helmethead];
	[helmethead release];
	
	// Rebonack
	NSImage *rebonack = [bossParts objectAtIndex:2];
	[rebonack lockFocus];
	[[bossParts objectAtIndex:3] compositeToPoint:NSMakePoint(16,16) operation:NSCompositeSourceOver];
	[rebonack unlockFocus];
	[tilesBosses addObject:rebonack];
	
	[tilesBosses addObject:[bossParts objectAtIndex:4]];	// Carock
	[tilesBosses addObject:[bossParts objectAtIndex:5]];	// Gooma
	
	// Barba
	NSImage *barba = [[NSImage alloc] initWithSize:NSMakeSize(38,128)];
	[barba lockFocus];
	[[bossParts objectAtIndex:6] compositeToPoint:NSMakePoint(0,112) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(18,96) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(20,80) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(22,64) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(20,48) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(18,32) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(16,16) operation:NSCompositeSourceOver];
	[[bossParts objectAtIndex:7] compositeToPoint:NSMakePoint(14,0) operation:NSCompositeSourceOver];
	[barba unlockFocus];
	[tilesBosses addObject:barba];
	[barba release];
	
	[tilesBosses addObject:[bossParts objectAtIndex:8]];	// Giant Bot
	
	[tilesBosses addObject:[bossParts objectAtIndex:9]];	// Thunderbird
	//[tilesBosses addObject:[bossParts objectAtIndex:9]];	// Dark Link
	
	/*NSString *path;
	NSData *ddd;
	for (i=0; i<[tilesBosses count]; i++) {
		path = [[NSString stringWithFormat:@"~/Desktop/TestTiles/enemy%02d.tiff",i] stringByExpandingTildeInPath];
		ddd = [[tilesBosses objectAtIndex:i] TIFFRepresentationUsingCompression:NSTIFFCompressionLZW factor:1.0];
		[ddd writeToFile:path atomically:YES];
	}*/
}

# pragma mark -

# pragma mark Attack

- (void)loadAttack
{
	ptr = [rom bytes] + 0x1E66D + 0x10;
	
	int i;
	unsigned char v;
	NSString *diff;
	for (i=0; i<9; i++) {
		v = *ptr++;
		[[matrixAttack cellWithTag:i] setIntValue:v];
		attack[i] = v;
		if (i == 0 || i == 8) continue;
		diff = [NSString stringWithFormat:@"+%d",attack[i] - attack[i-1]];
		[[matrixAttack cellAtRow:i column:1] setStringValue:diff];
	}
}

- (IBAction)changeAttack:(id)sender
{
	int r = [sender selectedRow];
	int nv = [[sender selectedCell] intValue];
	if (nv < 1) nv = 1;
	if (nv > 255) nv = 255;
	[[sender selectedCell] setIntValue:nv];
	attack[r] = nv;
	
	int i;
	unsigned char v;
	int d;
	NSString *diff;
	for (i=0; i<9; i++) {
		v = attack[i];
		[[matrixAttack cellAtRow:i column:0] setIntValue:v];
		if (i == 0 || i == 8) continue;
		d = attack[i] - attack[i-1];
		if (d < 0) diff = [NSString stringWithFormat:@"%d",d];
		else diff = [NSString stringWithFormat:@"+%d",d];
		[[matrixAttack cellAtRow:i column:1] setStringValue:diff];
	}
}

- (void)saveAttack
{
	[rom replaceBytesInRange:NSMakeRange( 0x1E66D + 0x10 , 9 ) withBytes:&attack[0]];
}

# pragma mark -

# pragma mark Magic

- (void)loadMagic
{
	ptr = [rom bytes] + 0x0D7B + 0x10;
	
	int i,j;
	unsigned char v;
	
	// Magic Usage //
	
	for (i=0; i<64; i++) {
		v = *ptr++;
		magic[i] = v;
		v /= 2;
		if (displayHex) [[matrixMagic cellWithTag:i] setStringValue:[objMain hexToString:v]];
		else [[matrixMagic cellWithTag:i] setIntValue:v];
	}
	
	// Magic Names //
	
	ptr = [rom bytes] + 0x1C2A + 0x10;
	
	unsigned char name[9];
	NSString *str;
	
	for (i=0; i<8; i++) {
		for (j=0; j<8; j++) {
			magicNames[i][j] = *ptr;
			name[j] = [self toASCII:(*ptr)];
			ptr++;
		}
		name[8] = NULL;
		str = [NSString stringWithCString:(const char *)name encoding:NSASCIIStringEncoding];
		[[matrixMagicNames cellAtRow:i column:0] setStringValue:str];
		ptr += 6;
	}
	
	// Magic Effects //
	
	ptr = [rom bytes] + 0x0DBB + 0x10;
	unsigned char e;
	
	for (i=0; i<8; i++) {
		e = *ptr++;
		magicEffects[i] = e;
		for (j=0; j<8; j++) {
			[[matrixMagicEffects cellAtRow:i column:j] setState:((e >> j) & 1)];
		}
	}
}

- (IBAction)changeMagic:(id)sender
{
	unsigned char t = [[sender selectedCell] tag];
	unsigned char nv = [[sender selectedCell] intValue];
	
	magic[t] = nv;
}

- (IBAction)changeMagicName:(id)sender
{
	
}

- (IBAction)changeMagicEffect:(id)sender
{
	
}

- (void)saveMagic
{
	int i;
	[rom replaceBytesInRange:NSMakeRange( 0x0D7B + 0x10 , 64 ) withBytes:&magic[0]];
	
	NSMutableString *name = [NSMutableString stringWithCapacity:8];
	unsigned char w[8];
	
	int j;
	for (i=0; i<8; i++) {
		[name setString:[[matrixMagicNames cellWithTag:i] stringValue]];
		for (j=0; j<8; j++) {
			w[j] = [self fromASCII:[name characterAtIndex:j]];
		}
		[rom replaceBytesInRange:NSMakeRange( 0x1C3A + (i * 14) , 8 ) withBytes:w];
	}
	
	unsigned char e[8];
	
	for (i=0; i<8; i++) {
		
		e[i] = 0;
		for (j=0; j<8; j++) {
			e[i] |= ([[matrixMagicEffects cellAtRow:i column:j] state] << j);
		}
	}
	[rom replaceBytesInRange:NSMakeRange( 0x0DCB , 8 ) withBytes:e];
}

# pragma mark -

# pragma mark Levels

- (void)setLevels
{
	unsigned int c;
	unsigned char b1,b2;
	ptr = [rom bytes] + 0x1669;
	
	int i;
	for (i=0; i<24; i++) {
		
		b1 = *ptr;
		b2 = *(ptr + 24);
		c = (b1 * 0x100) + b2;
		[[matrixLevels cellWithTag:i] setStringValue:[objMain decToString:c]];
		ptr++;
		
	}
}

- (void)setLevelsNames
{
	unsigned char name[8];
	NSString *str;
	int i,j;
	
	ptr = [rom bytes] + 0x1BF9;
	
	for (i=0; i<3; i++) {
		
		for (j=0; j<6; j++) {
			name[j] = *ptr++;
			name[j] = [self toASCII:name[j]];
		}
		name[j] = NULL;
			
		str = [NSString stringWithCString:(const char *)name encoding:NSASCIIStringEncoding];
		[[matrixLevelsNames cellWithTag:i] setStringValue:str];
		ptr += 8;
		
	}
}

- (void)saveLevels
{
	unsigned char v[72];
	unsigned char x;
	unsigned short t;
	NSString *str;
	
	int i,j;
	for (i=0; i<24; i++) {
		
		t = [[matrixLevels cellWithTag:i] intValue];
		v[i] = (t >> 8);
		v[i+24] = t;
		
	}
	[rom replaceBytesInRange:NSMakeRange( 0x1669 , 48 ) withBytes:v];
	
	for (i=0; i<24; i++) {
		
		if ([[matrixLevels cellWithTag:i] intValue] < 10) [[matrixLevels cellWithTag:i] setIntValue:10];
		str = [[matrixLevels cellWithTag:i] stringValue];
		for (j=0; j<3; j++) {
			
			if (((signed)[str length] - j - 2) < 0)
				x = 0x54;		// 0x54 + 0xA0 = 0xF4
			else
				x = [str characterAtIndex:([str length] - j - 2)];
			
			v[i+(j*24)] = x + 0xA0;		// 0xD0 - 0x30 = 0xA0
		}
	}
	[rom replaceBytesInRange:NSMakeRange( 0x1E42 , 72 ) withBytes:v];
}

# pragma mark -

# pragma mark Text

- (void)setTextStrings
{
	const char *str;
	unsigned short t = 0;
	unsigned char s[160];
	
	NSString *final;
	NSMutableArray *dialogs = [NSMutableArray arrayWithCapacity:98];
	
	ptr = [rom bytes] + 0xEFBE + 0x10;
	
	int i,j;
	for (i=0; i<98; i++) {
		
		t = (*ptr) & 0x00FF;
		t += *(ptr + 1) << 8;
		t += 0x4000 + 0x10;
		
		str = [rom bytes] + t;
		
		j = 0;
		while (1) {
			s[j] = *str++;
			if (s[j] == 0xFF) break;
			s[j] = [self toASCII:s[j]];
			j++;
		}
		
		s[j] = NULL;
		
		final = [NSString stringWithCString:(const char *)s encoding:NSASCIIStringEncoding];
		[dialogs addObject:final];
		
		ptr += 2;
	}
	
	//NSLog(@"final : \r%@",[dialogs description]);
	
	NSMutableString *strs = [NSMutableString stringWithString:@"\n"];
	for (i=0; i<[dialogs count]; i++) {
		[strs appendString:[NSString stringWithFormat:@"%X\n%@\n\n",i,[dialogs objectAtIndex:i]]];
	}
	//NSLog(str);
	
	// Chokes on Shadow of Night
	
	NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:dialogs,@"List",@"DIALOGS",@"Name",nil];
	[textStrings addObject:dict];
	[browserText reloadColumn:0];
}

- (IBAction)showText:(id)sender
{
	int s = [sender selectedRowInColumn:1];
	
	if (s == -1) {
		[fieldText setString:@" "];
		[fieldText setEditable:NO];
		[fieldText setSelectable:NO];
	} else {
		NSArray *list = [[textStrings objectAtIndex:[sender selectedRowInColumn:0]] objectForKey:@"List"];
		[fieldText setString:[list objectAtIndex:s]];
		[fieldText setSelectable:YES];
		[fieldText setEditable:YES];
	}
	
	// Redraw Dialog Box Matrix //
	
	int i,j;
	unsigned char t;
	for (i=0; i<10; i++) {
		for (j=0; j<14; j++) {
			t = 0xF4;	// Default Tile - Space
			if (j == 0 || j == 13) t = 0xCC;				// Vertical Borders
			if (i == 0 || i == 9) t = 0xCB;					// Horizontal Borders
			if (i == 0 && (j == 0 || j == 13)) t = 0xCA;	// Top Corners
			if (i == 9 && (j == 0 || j == 13)) t = 0xCA;	// Bottom Corners
			[[matrixText cellAtRow:i column:j] setImage:[tiles objectAtIndex:t]];
		}
	}
	
	int line = 2;
	int col = 2;
	int skipLine = 1;
	unsigned int offset;
	
	ptr = [rom bytes] + 0xEFBE + (s * 2) + 0x10;
	offset = *ptr | *(ptr + 1) << 8;
	offset += 0x4000;
	ptr = [rom bytes] + offset + 0x10;
	
	for (i=0; i<0x50; i++) {
		t = *ptr++;
		if (t == 0xFF) break;	// End of Sequence
		if (t == 0xFD || t == 0xFE) {
			line += skipLine + 1;
			col = 2;
			continue;
		}
		[[matrixText cellAtRow:line column:col] setImage:[tiles objectAtIndex:t]];
		col++;
	}
}

- (IBAction)confirmText:(id)sender
{
	int s = [browserText selectedRowInColumn:1];
	
	if (s >= 0) {
		NSMutableArray *list = [[textStrings objectAtIndex:[browserText selectedRowInColumn:0]] objectForKey:@"List"];
		NSString *bla = [NSString stringWithString:[fieldText string]];
		[list replaceObjectAtIndex:s withObject:bla];
		[browserText reloadColumn:1];
		[browserText selectRow:s inColumn:1];
	}
}

- (void)saveText
{
	unsigned short pt;		// Location of text data
	unsigned short pp;		// Location of text pointers
	unsigned short vp;		// Value of the current pointer
	unsigned char s[160];
	NSArray *list = [[textStrings objectAtIndex:0] objectForKey:@"List"];
	NSString *str;
	
	pt = 0xE390;
	pp = 0xEFCE;
	
	int i,j;
	for (i=0; i<98; i++) {
		
		str = [list objectAtIndex:i];
		if ((pt + [str length]) >= 0xEFCE) pt = 0xF830;		// Unused location in the ROM
		
		vp = pt - 0x4010;
		vp = (vp << 8) | (vp >> 8);
		
		for (j=0; j<[str length]; j++) {
			s[j] = [self fromASCII:[str characterAtIndex:j]];
		}
		
		s[j] = 0xFF;
		j++;
		
		//NSLog(@"pt : %X",pt);
		//NSLog(@"vp : %X",vp);
		
		[rom replaceBytesInRange:NSMakeRange( pt , j ) withBytes:s];
		[rom replaceBytesInRange:NSMakeRange( pp , 2 ) withBytes:&vp];
		
		pt += j;
		pp += 2;
	}
}

# pragma mark -

# pragma mark Enemies

- (void)loadEnemyAttributes
{
	int i,j;
	unsigned int offsets[6] = { 0x5421 , 0x9421 , 0xD421 , 0x11421 , 0x12921 , 0x15421 };
	
	// Hit Points //
	
	for (i=0; i<6; i++) {
		ptr = [rom bytes] + offsets[i] + 0x10;
		for (j=0; j<0x24; j++) {
			enemyHP[i][j] = *ptr++;
		}
	}
	
	// Enemy Attributes 1 //
	
	for (i=0; i<6; i++) {
		ptr = [rom bytes] + offsets[i] + 0xB4 + 0x10;
		for (j=0; j<0x24; j++) {
			enemyAttributes1[i][j] = *ptr++;
		}
	}
	
	// Enemy Attributes 2 //
	
	for (i=0; i<6; i++) {
		ptr = [rom bytes] + offsets[i] + 0xD8 + 0x10;
		for (j=0; j<0x24; j++) {
			enemyAttributes2[i][j] = *ptr++;
		}
	}
	
	// Enemy Attributes 3 //
	
	for (i=0; i<6; i++) {
		ptr = [rom bytes] + offsets[i] + 0x120 + 0x10;
		for (j=0; j<0x24; j++) {
			enemyAttributes3[i][j] = *ptr++;
		}
	}
}

- (void)loadExperience
{
	int i;
	unsigned short v;
	ptr = [rom bytes] + 0x1DDC0 + 0x10;
	
	for (i=0; i<16; i++) {
		v = *ptr;
		v += *(ptr + 0x1C) * 0x100;
		exp[i] = v;
		ptr++;
	}
	
	[tableExperience reloadData];
}

- (void)loadDamage
{
	int i,j;
	ptr = [rom bytes] + 0x1E2AF + 0x10;
	
	for (i=0; i<8; i++) {
		for (j=0; j<8; j++) {
			damage[i][j] = *ptr++;
		}
	}
	
	[tableDamage reloadData];
}

- (IBAction)changeWorld:(id)sender
{
	[menuEnemy removeAllItems];
	
	int i,p;
	unsigned char w = [[sender selectedItem] tag];
	NSString *name;
	for (i=0; i<0x24; i++) {
		name = [objSideView getEnemyName:i world:w];
		[menuEnemy addItemWithTitle:[NSString stringWithFormat:@"%02X - %@",i,name]];
	}
	
	// Palettes Matrix //
	
	ptr = [rom bytes] + 0x409E + 0x10;
	for (i=0; i<0x10; i++) {
		p = *ptr++;
		if (p == 0xFF) continue;
		[[matrixEnemyPalette cellAtRow:0 column:i-1] setBackgroundColor:[objMain colorForCode:p]];
		[[matrixEnemyPalette cellAtRow:0 column:i-1] setBordered:NO];
	}
	
	////
	
	[menuEnemy selectItemAtIndex:0];
	
	[self changeEnemy:menuEnemy];
}

- (IBAction)changeEnemy:(id)sender
{
	unsigned char hp;
	unsigned char a1,a2,a3;
	
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	hp = enemyHP[w][e];
	a1 = enemyAttributes1[w][e];
	a2 = enemyAttributes2[w][e];
	a3 = enemyAttributes3[w][e];
	
	//unsigned char enemyAttributes1[6][0x24];
	// xx.. ....	Palette Code (0-3)
	// ..x. ....	No Damage from Sword (needs Fire)
	// ...x ....	Steals Experience Points
	// .... xxxx	Experience Code (0-F)
	
	//unsigned char enemyAttributes2[6][0x24];
	// xx.. ....	Item Type (0 = gives no items, 1 = minor item, 2 = major item)
	// ..x. ....	Immune to Flying Blade and Fire
	// ...x ....	?
	// .... xxxx	Damage Code
	
	//unsigned char enemyAttributes3[6][0x24];
	// x... ....	Immune to Thunder Spell
	// .x.. ....	Regenerates
	// ..x. ....	?
	// ...x ....	Not hittable with sword
	// .... xxxx	?
	
	unsigned char expCode = a1 & 0x0F;
	unsigned char paletteCode = (a1 & 0xC0) >> 6;
	unsigned char damageCode = a2 & 0x0F;
	unsigned char itemType = (a2 & 0xC0) >> 6;
	
	BOOL steals = (a1 & 0x10) >> 4;
	BOOL noDamageFromSword = (a1 & 0x20) >> 5;
	BOOL immuneToFlyingBlade = (a2 & 0x20) >> 5;
	BOOL immuneToThunder = (a3 & 0x80) >> 7;
	BOOL regenerates = (a3 & 0x40) >> 6;
	
	//NSLog(@"index = %i",[sender indexOfSelectedItem]);
	//NSLog(@"bits : %X",bits);
	
	[fieldHP setIntValue:enemyHP[w][e]];
	[menuExpCode selectItemAtIndex:expCode];
	[textExperience setStringValue:[NSString stringWithFormat:@"%d",exp[expCode]]];
	
	NSRect bp = boxPaletteBasePosition;
	bp.origin.x += paletteCode * 64;
	[boxPalette setFrame:bp];
	
	[menuDamageCode selectItemAtIndex:damageCode];
	[menuItemType selectItemAtIndex:itemType];
	
	[checkSteals setState:steals];
	[checkNeedsFire setState:noDamageFromSword];
	[checkFlyingBlade setState:immuneToFlyingBlade];
	[checkImmuneThunder setState:immuneToThunder];
	[checkRegenerates setState:regenerates];
	
	//[checkFire setState:( (bits & 0x20) >> 5)];
	//[checkSteals setState:( (bits & 0x10) >> 4)];
	
	NSImage *imageToUse = [[tilesEnemies objectAtIndex:w] objectAtIndex:e];
	if (w == 3) {
		if (e == 0x20) imageToUse = [tilesBosses objectAtIndex:0];
		if (e == 0x21) imageToUse = [tilesBosses objectAtIndex:1];
	}
	if (w == 4) {
		if (e == 0x20) imageToUse = [tilesBosses objectAtIndex:2];
		if (e == 0x21) imageToUse = [tilesBosses objectAtIndex:5];
		if (e == 0x22) imageToUse = [tilesBosses objectAtIndex:3];
	}
	if (w == 5) {
		if (e == 0x1E) imageToUse = [tilesBosses objectAtIndex:6];
		if (e == 0x22) imageToUse = [tilesBosses objectAtIndex:7];
		if (e == 0x23) imageToUse = [NSImage imageNamed:@"DarkLinkTrigger"];
	}
	[imageEnemy setImage:imageToUse];
	
	[tableExperience selectRowIndexes:[NSIndexSet indexSetWithIndex:expCode] byExtendingSelection:NO];
	[tableDamage selectRowIndexes:[NSIndexSet indexSetWithIndex:damageCode] byExtendingSelection:NO];
	
	// To do : Towns section has different attributes
	// Change the flags labels, and hide some checkboxes, if needed
	// Is an enemy, tile mapping code (offset), enemy is immobile
	
	[self changeHitTable];
}

- (void)changeHitTable
{
	signed int i,j,k;
	for (i=0; i<9; i++) {
		k = 0;
		for (j = [fieldHP intValue]; j > 0; j -= attack[i]) {
			k++;
		}
		hit[i] = k;
	}
	
	[tableHits reloadData];
}

- (IBAction)changeHP:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	unsigned char nv = [fieldHP intValue];
	
	if (nv > 0xFF) {
		NSBeep();
		nv = 0xFF;
	}
	
	if (nv < 1) {
		NSBeep();
		nv = 1;
	}
	
	[fieldHP setIntValue:nv];
	enemyHP[w][e] = nv;
	
	[self changeHitTable];
}

- (IBAction)changeExpCode:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	unsigned char nv = [menuExpCode indexOfSelectedItem];
	
	enemyAttributes1[w][e] &= 0xF0;
	enemyAttributes1[w][e] |= nv;
	
	[textExperience setStringValue:[NSString stringWithFormat:@"%d",exp[nv]]];
}

- (IBAction)changeDamageCode:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	unsigned char nv = [menuDamageCode indexOfSelectedItem];
	
	enemyAttributes2[w][e] &= 0xF0;
	enemyAttributes2[w][e] |= nv;
}

- (IBAction)changeItemType:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	unsigned char nv = [menuItemType indexOfSelectedItem];
	nv <<= 6;
	
	enemyAttributes2[w][e] &= 0x3F;
	enemyAttributes2[w][e] |= nv;
}

- (IBAction)changeEnemyPalette:(id)sender
{
	int c = [sender selectedColumn];
	if (c == 3 || c == 7 || c == 11) return;
	
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	unsigned char nv = (c / 4) << 6;
	
	// Enemy Attributes 1
	// xx.. ....	Palette Code (0-3)
	// ..x. ....	No Damage from Sword (needs Fire)
	// ...x ....	Steals Experience Points
	// .... xxxx	Experience Code (0-F)
	
	enemyAttributes1[w][e] &= 0x3F;
	enemyAttributes1[w][e] |= nv;
	
	c /= 4;
	
	NSRect bp = boxPaletteBasePosition;
	bp.origin.x += c * 64;
	[boxPalette setFrame:bp];
}

- (IBAction)changeSteals:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	BOOL s = [sender state];
	
	enemyAttributes1[w][e] &= 0xEF;
	if (s) enemyAttributes1[w][e] |= 0x10;
}

- (IBAction)changeNeedsFire:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	BOOL s = [sender state];
	
	enemyAttributes1[w][e] &= 0xDF;
	if (s) enemyAttributes1[w][e] |= 0x20;
}

- (IBAction)changeFlyingBlade:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	BOOL s = [sender state];
	
	enemyAttributes2[w][e] &= 0xDF;
	if (s) enemyAttributes2[w][e] |= 0x20;
}

- (IBAction)changeImmuneThunder:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	BOOL s = [sender state];
	
	enemyAttributes3[w][e] &= 0x7F;
	if (s) enemyAttributes3[w][e] |= 0x80;
}

- (IBAction)changeRegenerates:(id)sender
{
	int w = [menuWorld indexOfSelectedItem];
	int e = [menuEnemy indexOfSelectedItem];
	
	BOOL s = [sender state];
	
	enemyAttributes3[w][e] &= 0xBF;
	if (s) enemyAttributes3[w][e] |= 0x40;
}

- (void)saveEnemies
{
	int i;
	unsigned int offset;
	unsigned int offsets[6] = { 0x5421 , 0x9421 , 0xD421 , 0x11421 , 0x12921 , 0x15421 };
	
	// Hit Points //
	
	for (i=0; i<6; i++) {
		offset = offsets[i] + 0x10;
		[rom replaceBytesInRange:NSMakeRange( offset , 0x24 ) withBytes:enemyHP[i]];
	}
	
	// Enemy Attributes 1 //
	
	for (i=0; i<6; i++) {
		offset = offsets[i] + 0xB4 + 0x10;
		[rom replaceBytesInRange:NSMakeRange( offset , 0x24 ) withBytes:enemyAttributes1[i]];
	}
	
	// Enemy Attributes 2 //
	
	for (i=0; i<6; i++) {
		offset = offsets[i] + 0xD8 + 0x10;
		[rom replaceBytesInRange:NSMakeRange( offset , 0x24 ) withBytes:enemyAttributes2[i]];
	}
	
	// Enemy Attributes 3 //
	
	for (i=0; i<6; i++) {
		offset = offsets[i] + 0x120 + 0x10;
		[rom replaceBytesInRange:NSMakeRange( offset , 0x24 ) withBytes:enemyAttributes3[i]];
	}
	
	// Experience Table //
	
	unsigned char nv[2][16];
	
	for (i=0; i<16; i++) {
		nv[0][i] = exp[i] & 0x00FF;
		nv[1][i] = (exp[i] & 0xFF00) >> 8;
	}
	
	[rom replaceBytesInRange:NSMakeRange( 0x1DDD0 , 16 ) withBytes:nv[0][i]];
	[rom replaceBytesInRange:NSMakeRange( 0x1DDEC , 16 ) withBytes:nv[1][i]];
}

# pragma mark -

# pragma mark Beginning

- (void)setBeginning
{
	ptr = [rom bytes] + 0x17AF7;
	
	int i;
	for (i=0; i<8; i++) {
		[[matrixBeginMagic cellWithTag:i] setState:*(ptr + i)];
		[[matrixBeginItems cellWithTag:i] setState:*(ptr + 10 + i)];
	}
	
	ptr += 0x08;
	[sliderBeginMC setIntValue:*ptr]; [textBeginMC setIntValue:*ptr];
	[sliderBeginHC setIntValue:*(ptr + 1)]; [textBeginHC setIntValue:*(ptr + 1)];
	
	ptr += 0x11;
	[sliderBeginCrystals setIntValue:*ptr];
	
	ptr += 0x02;
	[[matrixBeginTechs cellWithTag:0] setState:(*ptr >> 4)];
	[[matrixBeginTechs cellWithTag:1] setState:((*ptr >> 2) & 0x01)];
	
	ptr = [rom bytes] + 0x1C369;
	[fieldBeginLives setIntValue:*ptr];
}

- (void)saveBeginning
{
	unsigned char s[18];
	
	int i;
	for (i=0; i<8; i++) {
		s[i] = [[matrixBeginMagic cellWithTag:i] state];
		s[i+10] = [[matrixBeginItems cellWithTag:i] state];
	}
	
	s[8] = [sliderBeginMC intValue];
	s[9] = [sliderBeginHC intValue];
	[rom replaceBytesInRange:NSMakeRange( 0x17AF7 , 18 ) withBytes:s];
	
	s[0] = [sliderBeginCrystals intValue];
	s[1] = 0;
	s[2] = ([[matrixBeginTechs cellWithTag:0] state] * 0x10) | ([[matrixBeginTechs cellWithTag:1] state] * 0x04);
	[rom replaceBytesInRange:NSMakeRange( 0x17B10 , 3 ) withBytes:s];
	
	s[0] = [fieldBeginLives intValue];
	[rom replaceBytesInRange:NSMakeRange( 0x1C369 , 1 ) withBytes:s];
	
}

# pragma mark -

# pragma mark Misc

- (void)setMisc
{
	ptr = [rom bytes] + 0x0E7A;
	[fieldMiscLife setIntValue:*ptr];
	
	ptr = [rom bytes] + 0x1E8B0;
	[fieldMiscItem setIntValue:*ptr];
	
	ptr = [rom bytes] + 0x1D4F3;
	if (*ptr == 0) [checkMiscBeep setState:NO];
	else [checkMiscBeep setState:YES];
	
	[self actionBeeping:checkMiscBeep];
	
	ptr = [rom bytes] + 0x1D4E5;
	[fieldMiscBeep setIntValue:*ptr];
}

- (IBAction)actionBeeping:(id)sender
{
	if ([sender state]) [textMiscBeep setTextColor:[NSColor blackColor]];
	else [textMiscBeep setTextColor:[NSColor lightGrayColor]];
	[fieldMiscBeep setEnabled:[sender state]];
	[fieldMiscBeep setEditable:[sender state]];
}

- (void)saveMisc
{
	unsigned char v;
	
	v = [fieldMiscLife intValue];
	[rom replaceBytesInRange:NSMakeRange( 0x0E7A , 1 ) withBytes:&v];
	
	v = [fieldMiscItem intValue];
	[rom replaceBytesInRange:NSMakeRange( 0x1E8B0 , 1 ) withBytes:&v];
	
	v = ([checkMiscBeep state] << 6);
	[rom replaceBytesInRange:NSMakeRange( 0x1D4F3 , 1 ) withBytes:&v];
	
	v = [fieldMiscBeep intValue];
	[rom replaceBytesInRange:NSMakeRange( 0x1D4E5 , 1 ) withBytes:&v];
}

# pragma mark -

- (unsigned char)toASCII:(unsigned char)ctc
{
	if (ctc >= 0xDA && ctc <= 0xF3) ctc -= 153;
	if (ctc >= 0xD0 && ctc <= 0xD9) ctc -= 160;
	if (ctc == 0x34) ctc = '?';
	if (ctc == 0x36) ctc = '!';
	if (ctc == 0x9C) ctc = ',';
	if (ctc == 0xCF) ctc = '.';
	if (ctc == 0xF4) ctc = ' ';
	if (ctc == 0xF6) ctc = '-';
	if (ctc == 0xFD) ctc = 0x0A;
	if (ctc == 0xFE) ctc = 0x0D;
	
	return ctc;
}

- (unsigned char)fromASCII:(unsigned char)ctc
{
	if (ctc >= 'A' && ctc <= 'Z') ctc += 153;
	if (ctc >= '0' && ctc <= '9') ctc += 160;
	if (ctc == '?') ctc = 0x34;
	if (ctc == '!') ctc = 0x36;
	if (ctc == ',') ctc = 0x9C;
	if (ctc == '.') ctc = 0xCF;
	if (ctc == ' ') ctc = 0xF4;
	if (ctc == '-') ctc = 0xF6;
	if (ctc == 0x0A) ctc = 0xFD;
	if (ctc == 0x0D) ctc = 0xFE;
	
	return ctc;
}

# pragma mark -

- (int)browser:(NSBrowser *)br numberOfRowsInColumn:(int)col
{
	if (col == 0)
		return [textStrings count];
	else
		return [[[textStrings objectAtIndex:[br selectedRowInColumn:0]] objectForKey:@"List"] count];
}

- (void)browser:(NSBrowser *)br willDisplayCell:(id)cell atRow:(int)row column:(int)col
{
	NSString *section;
	NSArray *fc;
	if (col == 0) {
		section = [[textStrings objectAtIndex:row] objectForKey:@"Name"];
		[cell setStringValue:section];
		[cell setLeaf:NO];
	} else {
		fc = [[textStrings objectAtIndex:[br selectedRowInColumn:0]] objectForKey:@"List"];
		NSString *str = [fc objectAtIndex:row];
		[cell setStringValue:str];
		[cell setLeaf:YES];
	}
}

- (int)numberOfVisibleColumns { return 1; }

- (id)tableView:(NSTableView *)tv objectValueForTableColumn:(NSTableColumn *)tc row:(int)row
{
	if (!rom) return nil;
	
	id obj = nil;
	int a;
	int col;
	
	if (tv == tableHits) {
		a = [[tc identifier] characterAtIndex:0];
		a -= 0x31;
		obj = [NSNumber numberWithInt:hit[a]];
	} else if (tv == tableExperience) {
		a = exp[row];
		if ([[tc identifier] isEqualTo:@"Type"]) {
			//if (row > 9) obj = [NSString stringWithFormat:@"%c",(row + 0x37)];
			//else obj = [NSNumber numberWithInt:row];
			obj = [NSString stringWithFormat:@"%X",row];
		} else {
			obj = [objMain decToString:a];
		}
	} else {
		col = [[tc dataCell] tag];
		if (col == 0) {
			obj = [NSString stringWithFormat:@"%i",row];
		} else {
			obj = [NSString stringWithFormat:@"%i",damage[row][col-1]];
		}
	}
	
	return obj;
}

- (void)tableView:(NSTableView *)tv setObjectValue:obj forTableColumn:(NSTableColumn *)tc row:(int)row
{
	int v = [obj intValue];
	int col = [[tc dataCell] tag];
	
	if (tv == tableExperience) exp[row] = v;
	if (tv == tableDamage) damage[row][col-1] = v;
}

- (int)numberOfRowsInTableView:(NSTableView *)tv
{
	if (!rom) return 0;
	
	if (tv == tableHits) return 1;
	if (tv == tableDamage) return 8;
	else return 16;
}

// To do : levels in the level-up menu must reflect the changes

// NEXT      1BE5
// ATTACK    1BF9
// MAGIC     1C07
// LIFE      1C15
// UP        1C1E
// CANCEL    1C23
// WILL      1D49
// GO UP     1D57

- (void)controlTextDidChange:(NSNotification *)notif
{
	id fe = [[notif userInfo] objectForKey:@"NSFieldEditor"];
	id mt = [[fe superview] superview];
	int s = [mt tag];
	
	if ([[fe string] length] > s) {
		[fe setTextColor:[NSColor redColor]];
	} else {
		[fe setTextColor:[NSColor blackColor]];
	}
}

@end
