gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > Background redone...still doesn't work

#20025 - CyberSlag5k - Fri Apr 30, 2004 6:12 am

Ok, I've gone through all my tutorials and read up on the hardware docs and now have what I feel is a fairly thurough understanding of tile backgrounds. I understand what the char base blocks are (something I was previously lost on) and most of the gaps in my comprehension have been filled by my latest studying. So, it is with no trepedation that I rewrote the background code in my program. Parts were based off my gbajunkie tutorials but I understand all that is going on.

Anyway, I think I've done everything (and it looks ok to me), but there's still no background showing up. Take a look:

Code:

//pretty basic background struct
typedef struct
{
   u16* tileData;
   u16* mapData;
   u8 mosaic;
   u8 colorMode;
   u8 number;
   u16 size;
   u8 charBaseBlock;
   u8 screenBaseBlock;
   u8 wrapAround;
   s16 posX, posY;
   s32 DX, DY;
   s16 PA, PB, PC, PD;
}Background;

Background back2;

//enables the background myBack points to
void enableBackground(Background *myBack)
{
   u16 temp;

   myBack->tileData = (u16*)CharBaseBlock(myBack->charBaseBlock);
   myBack->mapData = (u16*)ScreenBaseBlock(myBack->screenBaseBlock);
   
   temp = myBack->size | (myBack->charBaseBlock << CHAR_SHIFT) | (myBack->screenBaseBlock << SCREEN_SHIFT) | myBack->colorMode | myBack->mosaic;

   switch(myBack->number)
   {
   case 0:
   {
      REG_BG0CNT = temp;
      REG_DISPCNT |= BG0_ENABLE;
    }break;
   case 1:
   {
      REG_BG1CNT = temp;
      REG_DISPCNT |= BG1_ENABLE;
    }break;
   case 2:
   {
      REG_BG2CNT = temp;
      REG_DISPCNT |= BG2_ENABLE;
    }break;
   case 3:
   {
      REG_BG3CNT = temp;
      REG_DISPCNT |= BG3_ENABLE;
    }break;

   default:
      break;

   }

}

int main()
{
//back2 setup stuff
   back2.number = 2;
   back2.charBaseBlock = 0;
   back2.screenBaseBlock = 24;
   back2.colorMode = BG_COLOR_256;
   back2.size = ROTBG_SIZE_256x256;
   back2.mosaic = 0;
   back2.posX = 0;
   back2.posY = 0;

   setMode(MODE_1 | OBJ_ENABLE | OBJ_MAP_1D);

//load my background palette into memory
   for(int i = 0; i < 256; i++)
   {
      BGPaletteMem[i] = bgPalette[i];
      OBJPaletteMem[i] = palette[i];
   }

//load my tile data into VRAM(1232 is the size of the array
//my map editor (MapEd) created so I just went with it
   for(int i = 0; i < 1232; i++)
      back2.tileData[i] = bgTiles[i];

//load my map data into VRAM. The map is 240x160 pixels, which is
//30x20 tiles (30*20 = 600)
   for(int i = 0; i < 600; i++)
      back2.mapData[i] = bgMap[i];

   enableBackground(&back2);
}


So.....am I doing something wrong? My sprites and stuff still work (I of course excluded the code for them) but my background viewer in mappyVM shows nothing for the tiles or map. It does, though, show a background palette (although a few of the colors are slightly suspect).

The only thing I can think I might be doing wrong deals with the map size. I created a map that was 240x160 pixels in size, though my background size is 256x256. I would think this would still be ok.

And another quick question: does map data only take up one screen base block?

Thanks as always!
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...

#20034 - NoMis - Fri Apr 30, 2004 8:34 am

i am missing something important in your programm. You have no main loop. A GBA programm never leaves the main function because it should have a loop like this:

Code:


 .... loading stuff comes here ....

while(1)
{
    ... all kinds of things ....
    Wait4Vblank();
    ... update the graphical stuff ...

}

#20035 - sajiimori - Fri Apr 30, 2004 8:36 am

Your program returns from main(), which resets the GBA using the crt0.s that comes with DKA.
Quote:

The only thing I can think I might be doing wrong deals with the map size. I created a map that was 240x160 pixels in size, though my background size is 256x256. I would think this would still be ok.

It's not ok because the hardware map is 16 cells wider, so you're copying the first 16 cells of your second map row into the last 16 tiles of the first hardware map row, and so on.

Also, map cells are 1 byte for rot/scale BGs, and you're copying 2 bytes at a time so you need to do 300 copies for a 30x20 map, not 600.
Quote:

And another quick question: does map data only take up one screen base block?

Depends on the map size. It's 1 block for a 32x32 text map, or 8 blocks for a 128x128 rot/scale map.

It's pretty obvious when you think about it. Each cell in a text BG is 2 bytes, a 32x32 map has 1024 cells, and with 2 bytes per cell it's 2048 bytes, which is the size of a screen base block.

#20045 - CyberSlag5k - Fri Apr 30, 2004 3:29 pm

Quote:

i am missing something important in your programm. You have no main loop. A GBA programm never leaves the main function because it should have a loop like this


I'm sorry, my loop is indeed there. I should have said that along with the sprite stuff I left out any of the things without direct berring on the background stuff (namely the main loop). Heh, and I suppose closing the main bracket was a little deceptive in this light.

Quote:

It's not ok because the hardware map is 16 cells wider, so you're copying the first 16 cells of your second map row into the last 16 tiles of the first hardware map row, and so on.


Yes, I can definitely see that being a problem. I'll redo my map. Thanks.

Quote:

Also, map cells are 1 byte for rot/scale BGs, and you're copying 2 bytes at a time so you need to do 300 copies for a 30x20 map, not 600.


Didn't know that. I'll correct it.



Thanks guy, I'll keep you posted.
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...

#20050 - CyberSlag5k - Fri Apr 30, 2004 6:40 pm

Ok, I've made the corrections, still have no background and I'm quite perplexed. Here's pretty much everything

map header:
Code:

const u16 bgMap[1024]ALIGN4 =
{
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x3000,0x3001,0x3002,0x3003,0x3000,0x3001,0x3002,0x3000,0x3030,0x5044,0x5044,0x5044,0x5044,0x5044,0x5044,
0x5044,0x5044,0x5044,0x5044,0x5044,0x5044,0x4031,0x3002,0x3003,0x3000,0x3001,0x3002,0x3003,0x3000,0x3001,0x0000,
0x0000,0x300c,0x3000,0x3000,0x3001,0x3002,0x3003,0x300e,0x3000,0x3034,0x5044,0x5045,0x5046,0x5045,0x5045,0x5045,
........


tile header
Code:

const u16 bgTiles[1232]ALIGN4 =
{
0x6533,0x5636,0x6553,0x5366,0x3555,0x4335,0x6356,0x75c5,0x5565,0x7326,0x4576,0x4773,0x3356,0x5644,0x4343,0x3553,
0x5566,0x6566,0x6656,0x3566,0x6556,0x6846,0x6655,0x6566,0x3666,0x6665,0x4565,0x3553,0x5444,0x6665,0x5334,0x6655,
0x8335,0x4533,0x5335,0x5354,0x3635,0x5538,0x5563,0x5653,0x5565,0x3653,0x5555,0x3345,0x6554,0x4336,0x3763,0x3544,
0x5343,0x3355,0x4444,0x3734,0x3434,0x4575,0x4443,0x3374,0x3334,0x5375,0x4357,0x3573,0x3534,0x3737,0x7443,0x5573,
0x2fc1,0x31fe,0xfee1,0x3e1f,0xe3e1,0xfd13,0x1133,0x301e,0x221f,0x22f3,0x221e,0xe14f,0x0ccc,0x3033,0x1ecc,0xf1e4,
0x0cf2,0xe001,0xce0c,0xf0e1,0x1013,0xf3ce,0x2e0f,0xe3f2,0x1d13,0x3e02,0x3cee,0x3221,0x1321,0xad32,0x146c,0x1021,
0xc0f3,0x2123,0x13ce,0xf333,0xc3ee,0x42ee,0x0f33,0x31ec,0xe23c,0x20dd,0x3fec,0xeede,0xef7e,0xcec1,0x0c13,0xfffc,
0x3323,0x2f43,0x12e1,0x23ee,0x0ef2,0x2fc0,0xc1e4,0x3ffe,0xfe22,0xf1c1,0x3ec1,0xe044,0x1e3e,0x3203,0xc131,0xcc23,
0xccfe,0x9e9c,0x99cf,0x9ee9,0x99f9,0xe9cf,0xff0e,0x0fcc,0x0999,0x9cf9,0xc9d9,0x9ff9,0xfde0,0xd09f,0xeede,0xbe99,
0xdece,0xef9c,0xc900,0xee99,0xd000,0xccc0,0xe00e,0xcbcf,0xde99,0xc990,0x999f,0xcdfc,0x990e,0xc9f9,0x999e,0xbccc,
0xeef0,0xed99,0xffc0,0x9c00,0xccff,0xfd99,0xccff,0xc0ff,0xfcfc,0xc00f,0x9fff,0xd9f0,0x9fcc,0xc990,0x9cff,0x0e9f,
.......


map palette:
Code:

const u16 bgPalette[256]ALIGN4 =
{
0x0000,0x67ff,0x4fff,0x33ff,0x1bff,0x03ff,0x7f3f,0x673f,0x4f3f,0x333f,0x1b3f,0x033f,0x7e7f,0x667f,0x4e7f,0x327f,
0x0000,0x6679,0x4e79,0x3279,0x1a79,0x0279,0x7d99,0x6599,0x4d99,0x3199,0x1999,0x0199,0x7cd9,0x64d9,0x4cd9,0x30d9,
0x0000,0x00c0,0x7c00,0x6400,0x4c00,0x3000,0x1800,0x0000,0x316e,0x292c,0x6f7c,0x2d6d,0x252b,0x2d4d,0x294c,0x252c,
0x0000,0x4212,0x0000,0x1e50,0x2271,0x1a2f,0x120f,0x19ee,0x7bff,0x73ff,0x21af,0x6fdf,0x2e35,0x25d2,0x3256,0x3ab9,
0x0000,0x3a77,0x3a98,0x42da,0x4afb,0x29b0,0x5b5d,0x216e,0x214c,0x6b5b,0x1d0a,0x210b,0x294c,0x0c7f,0x421f,0x039b,
0x0000,0x00c0,0x7c00,0x6400,0x4c00,0x3000,0x1800,0x0000,0x1908,0x29ad,0x214a,0x4ef7,0x4a94,0x18e7,0x3e31,0x5b39,
0x0000,0x4231,0x4a73,0x1909,0x214b,0x4eb6,0x14e8,0x36df,0x2638,0x214c,0x31d0,0x21d4,0x31d0,0x0d9e,0x7fff,0x0c63,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
};


main program (in its entirety this time)
Code:

//gba test
//main.cpp

#include"gba.h"
#include"soldier.h"
#include"BG_Palette.cpp"
#include"BG_Maps.cpp"
#include"BG_Tiles.cpp"

#define DMA_C

using namespace std;

typedef struct
{
   int posX, posY;
   u16 spriteFrame[18];
   int activeFrame;
   u16 OAMSpriteNum;
}Sprite;

typedef struct
{
   u16* tileData;
   u16* mapData;
   u8 mosaic;
   u8 colorMode;
   u8 number;
   u16 size;
   u8 charBaseBlock;
   u8 screenBaseBlock;
   u8 wrapAround;
   s16 posX, posY;
   s32 DX, DY;
   s16 PA, PB, PC, PD;
}Background;

Background back2;

Sprite soldier;

bool open = true;

u16* videoBuffeer = ((u16*)0x6000000);
u16* paletteMem = ((u16*)0x5000000);
u16* OAM = ((u16*)0x7000000);

u16 const *myArray[19] = {obj0, obj1, obj2, obj3, obj4, obj5, obj6, obj7, obj8, obj9, obj10, obj11, obj12, obj13, obj14, obj15, obj16, obj17};

OAMEntry sprites[128];
pRotData rotData = (pRotData)sprites;

void enableBackground(Background *myBack)
{
   u16 temp;

   myBack->tileData = (u16*)CharBaseBlock(myBack->charBaseBlock);
   myBack->mapData = (u16*)ScreenBaseBlock(myBack->screenBaseBlock);
   
   temp = myBack->size | (myBack->charBaseBlock << CHAR_SHIFT) | (myBack->screenBaseBlock << SCREEN_SHIFT) | myBack->colorMode | myBack->mosaic;

   switch(myBack->number)
   {
   case 0:
   {
      REG_BG0CNT = temp;
      REG_DISPCNT |= BG0_ENABLE;
    }break;
   case 1:
   {
      REG_BG1CNT = temp;
      REG_DISPCNT |= BG1_ENABLE;
    }break;
   case 2:
   {
      REG_BG2CNT = temp;
      REG_DISPCNT |= BG2_ENABLE;
    }break;
   case 3:
   {
      REG_BG3CNT = temp;
      REG_DISPCNT |= BG3_ENABLE;
    }break;

   default:
      break;

   }

}
   

void copyOAM()
{
   DMACopy(3, (void*)sprites, (void*)OAM, 512, DMA_16NOW);
}

void DMACopy(u8 channel, void* source, void* dest, u32 wordCount, u32 mode)
{
   switch(channel)
   {
   case 0:
      REG_DMA0SAD = (u32)source;
      REG_DMA0DAD = (u32)dest;
      REG_DMA0CNT = wordCount | mode;
   break;
   case 1:
      REG_DMA1SAD = (u32)source;
      REG_DMA1DAD = (u32)dest;
      REG_DMA1CNT = wordCount | mode;
   break;
   case 2:
      REG_DMA2SAD = (u32)source;
      REG_DMA2DAD = (u32)dest;
      REG_DMA2CNT = wordCount | mode;
   break;

   case 3:
      REG_DMA3SAD = (u32)source;
      REG_DMA3DAD = (u32)dest;
      REG_DMA3CNT = wordCount | mode;
   break;
   }
}

void initializeSprites()
{
   for(u16 i = 0; i < 128; i++)
   {
      sprites[i].attribute0 = 160;
      sprites[i].attribute1 = 240;
   }
}

void VSync()
{
   while((volatile u16)REG_VCOUNT != 160)
   {}
}

void setMode(u16 mode)
{
   REG_DISPCNT = mode;
}

void getInput()
{
   if(!(*KEYS & KEY_LEFT))
   {
      soldier.posX -= 1;
   }
   if(!(*KEYS & KEY_DOWN))
   {
      soldier.posY += 1;

   }
   if(!(*KEYS & KEY_RIGHT))
   {
      soldier.posX += 1;
   }
   if(!(*KEYS & KEY_UP))
   {
      soldier.posY -= 1;
   }
   if(!(*KEYS & KEY_A))
   {
      open = true;
      REG_TM0D = 0;
      //soldier.posX -= 1;
   }
   if(!(*KEYS & KEY_B))
   {
      open = false;
      REG_TM0D = 0;
      //soldier.posX += 1;
   }
   if(!(*KEYS & KEY_L))
   {

   }
   if(!(*KEYS & KEY_R))
   {

   }
   if(!(*KEYS & KEY_SELECT))
   {

   }
   if(!(*KEYS & KEY_START))
   {

   }
}

void updateSprites(OAMEntry *spritePointer)
{
   spritePointer->attribute0 &= ~0x00ff;
   spritePointer->attribute0 |= (soldier.posY & 0x00ff);

   spritePointer->attribute1 &= ~0x01ff;
   spritePointer->attribute1 |= (soldier.posX & 0x00ff);

   if(REG_TM0D  > 200)
   {
      if(open && soldier.activeFrame > 0)
      {
         REG_TM0D  = 0;
         soldier.activeFrame--;
      }
      if((!open) && soldier.activeFrame < 17)
      {
         REG_TM0D  = 0;
         soldier.activeFrame++;
      }
   }

   DMACopy(3, (void*)myArray[soldier.activeFrame], (void*)spriteMem, 2048, DMA_16NOW);
}

int main()
{
   soldier.posX = 20;
   soldier.posY = 40;

   back2.number = 2;
   back2.charBaseBlock = 0;
   back2.screenBaseBlock = 24;
   back2.colorMode = BG_COLOR_256;
   back2.size = ROTBG_SIZE_256x256;
   back2.mosaic = 0;
   back2.posX = 0;
   back2.posY = 0;

   REG_TM0CNT  = TIMEENABLE | TIME1024;
   REG_TM0D  = 0;
   setMode(MODE_1 | OBJ_ENABLE | OBJ_MAP_1D);

   for(int i = 0; i < 256; i++)
   {
      BGPaletteMem[i] = bgPalette[i];
      OBJPaletteMem[i] = palette[i];
   }

   for(int i = 0; i < 1232; i++)
      back2.tileData[i] = bgTiles[i];

   for(int i = 0; i < 512; i++)
      back2.mapData[i] = bgMap[i];

   enableBackground(&back2);


   initializeSprites();

   sprites[0].attribute0 = COLOR_256 | SQUARE | soldier.posY;
   sprites[0].attribute1 = SIZE_64 | soldier.posX;
   sprites[0].attribute2 = 0 | PRIORITY(0);

   soldier.OAMSpriteNum = 0;
   soldier.activeFrame = 0;


   while(1)
   {
      getInput();
      updateSprites(&sprites[0]);
      VSync();
      copyOAM();
   }

   return 0;
}


I hate to throw a full source dump at you guys, but I'm kind of at a loss. Everything I'm reading says to do something pretty much like what I'm doing. Do you guys see anything?

Thanks as always.
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...

#20051 - sajiimori - Fri Apr 30, 2004 6:50 pm

If this is your first attempt at backgrounds, write a shorter program that only uses backgrounds, without any fancy data structures.

Write the shortest program you can imagine that shows a background.

Edit: The mistake isn't apparent because of the awkward BG struct. The tileData and mapData pointers are set when you call enableBackground(), but you are using the pointers before you call that function.

#20057 - dagamer34 - Fri Apr 30, 2004 10:51 pm

Have you looked at the VBA viewer to see what is actually loaded into memory? Also take a look at the IO Viewer, Map Viewer, and Tile Viewer as they may be helpful to you in solving what is wrong.
_________________
Little kids and Playstation 2's don't mix. :(

#20078 - CyberSlag5k - Sat May 01, 2004 4:22 pm

My problem was that MapEd does not support 256 color maps.

Thanks for everyone's help!
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...

#20094 - yaustar - Sat May 01, 2004 11:11 pm

for 256 colour map editing, you best bet would be Map Beta 4 I think... fairly crude though...
_________________
[Blog] [Portfolio]

#20097 - CyberSlag5k - Sun May 02, 2004 12:15 am

I've switch to mappy. It's working out ok but the mapData output is in base 10 and everything else is in hex. I think it's causing me some problems.

Also, am I correct in assuming I can have no more than 256 tiles per map?
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...

#20099 - dagamer34 - Sun May 02, 2004 12:27 am

Actually, if you use mapEd only as a map-editor and use another program to convert images, you can use 256-colored tiles. You just have to make sure that you choose un-optimized mode when creating a new map.
_________________
Little kids and Playstation 2's don't mix. :(

#20118 - sajiimori - Sun May 02, 2004 4:35 pm

Quote:

I've switch to mappy. It's working out ok but the mapData output is in base 10 and everything else is in hex. I think it's causing me some problems.

It doesn't matter what base numbers are written in. The distinction is lost as soon as the compiler parses them.
Quote:

Also, am I correct in assuming I can have no more than 256 tiles per map?

I'm not seeing that limitation.

#20120 - CyberSlag5k - Sun May 02, 2004 5:28 pm

Quote:
I'm not seeing that limitation.


Well, if the map sees my tiles as an 8 byte hex code (0x09, 0x2E), wouldn't the maximum number I can load be 0xFF which is 256?
_________________
When you find yourself in the company of a halfling and an ill-tempered Dragon, remember, you do not have to outrun the Dragon...

#20163 - niltsair - Mon May 03, 2004 2:23 pm

Map entries (in text mode, not rotation) takes 10bits for the index of the tile, which means 1024 accessible tiles. The remaning 6bits are used to flip the tiles and select a palette when in 16colors mode.
_________________
-Inside every large program is a small program struggling to get out. (Hoare's Law of Large Programs)
-The man who can smile when things go wrong has thought of someone he can blame it on. (Nixon's Theorem)